I have this function from : https://rosettacode.org/wiki/Combinations#ES6
In my environementt console.log(show(comb(3,15)));
(same as this snippet bellow) take aprox. 4 seconds to process
If I try console.log(show(comb(3,16)));
that take aprox. 16 seconds
If I try console.log(show(comb(3,17)));
that take aprox. 90 seconds
But If I tryed : console.log(show(comb(3,20)));
After one hour of process are not yet finish and I have stopped it.
The question is:
How to calculate beforehand the time to process comb(3,50)
or comb(3,80)
?
(() => {
'use strict';
// COMBINATIONS -----------------------------------------------------------
// comb :: Int -> Int -> [[Int]]
const comb = (m, n) => combinations(m, enumFromTo(0, n - 1));
// combinations :: Int -> [a] -> [[a]]
const combinations = (k, xs) =>
sort(filter(xs => k === xs.length, subsequences(xs)));
// GENERIC FUNCTIONS -----------------------------------------------------
// cons :: a -> [a] -> [a]
const cons = (x, xs) => [x].concat(xs);
// enumFromTo :: Int -> Int -> [Int]
const enumFromTo = (m, n) =>
Array.from({
length: Math.floor(n - m) + 1
}, (_, i) => m + i);
// filter :: (a -> Bool) -> [a] -> [a]
const filter = (f, xs) => xs.filter(f);
// foldr (a -> b -> b) -> b -> [a] -> b
const foldr = (f, a, xs) => xs.reduceRight(f, a);
// isNull :: [a] -> Bool
const isNull = xs => (xs instanceof Array) ? xs.length < 1 : undefined;
// show :: a -> String
const show = x => JSON.stringify(x) //, null, 2);
// sort :: Ord a => [a] -> [a]
const sort = xs => xs.sort();
// stringChars :: String -> [Char]
const stringChars = s => s.split('');
// subsequences :: [a] -> [[a]]
const subsequences = xs => {
// nonEmptySubsequences :: [a] -> [[a]]
const nonEmptySubsequences = xxs => {
if (isNull(xxs)) return [];
const [x, xs] = uncons(xxs);
const f = (r, ys) => cons(ys, cons(cons(x, ys), r));
return cons([x], foldr(f, [], nonEmptySubsequences(xs)));
};
return nonEmptySubsequences(
(typeof xs === 'string' ? stringChars(xs) : xs)
);
};
// uncons :: [a] -> Maybe (a, [a])
const uncons = xs => xs.length ? [xs[0], xs.slice(1)] : undefined;
// TEST -------------------------------------------------------------------
// return show(
// comb(3, 5)
// );
console.log(show(comb(3,15)));
})();
Use binomial coefficients. The time to process comb(3,n)
is n choose 3
which works out to n*(n-1)*(n-2)/6
hence is O(n^3)
. For example, increasing n
by a factor of 10 should increase the runtime by a factor of roughly 1000.
20 choose 3
is only 1140, so if it takes over an hour to generate them, the algorithm in question isn't particularly good. Furthermore, the gap between 20 choose 3
and 17 choose 3
is not so large that it really explains the time difference. Thus, the asymptotic analysis is only suggestive of what is happening. The actual runtime seems to be much worse.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With