Specific combination algorithm - javascript

If I have n balls and k containers then this -> ( (n+k-1)! / n!(k-1)! ) will work out how many combinations there are.
I am having difficulty changing this to produce a list of all combinations in javascript.
In a function taking an array of balls and some amount of containers.
combinations([1,2,3,4,5,6], 3)
Each container can have any number of balls and containers can be empty.
Here is something i attempted but im only getting one ball in each container.
function generateCombinations(array, r, callback) {
function equal(a, b) {
for (var i = 0; i < a.length; i++) {
if (a[i] != b[i]) return false;
}
return true;
}
function values(i, a) {
var ret = [];
for (var j = 0; j < i.length; j++) ret.push(a[i[j]]);
return ret;
}
var n = array.length;
var indices = [];
for (var i = 0; i < r; i++) indices.push(i);
var final = [];
for (var i = n - r; i < n; i++) final.push(i);
while (!equal(indices, final)) {
callback(values(indices, array));
var i = r - 1;
while (indices[i] == n - r + i) i -= 1;
indices[i] += 1;
for (var j = i + 1; j < r; j++) indices[j] = indices[i] + j - i;
}
callback(values(indices, array));
}
count = 0
generateCombinations([1,2,3,4,5,6,7,8,9,1],3,function(first){
$("#hello").append(first+"<br />")
count = count +1
})
$("#hello").append(count)

You can do it in this way:
var containers = [];
// n - number of balls, k - number of containers
function dfs(n, k) {
// Ending point of recursion, all balls are placed
if(n == 0) {
var output = [];
for(var i = 0; i < k; i++) {
output.push('{' + containers[i].join(', ') + '}');
}
output = '[' + output.join(', ') + ']';
console.log(output);
return;
}
// Try to put ball #n
for(var i = 0; i < k; i++) {
containers[i].push(n);
// Now we have placed ball #n, so we have 1 .. n - 1 balls only
dfs(n - 1, k);
// Remove ball when back to use again
containers[i].pop();
}
}
var n = 4;
var k = 3;
for(var i = 0; i < k; i++) {
containers[i] = [];
}
dfs(n, k);

I initially thought you wanted all the combinations of k elements out of n, but your problem is different, it's partitioning n elements in k parts.
When going through the elements, at each steps, you may choose to put the current element in any container, that's k possibilities. In total, you will have kn possible solutions.
Therefore, it would be faster to iterate through all the solutions, rather than storing them in an array.
You can represent a solution as a unique number in base k, with n digits, and iterate through the solutions by incrementing that number.
In your example, the base is 3, and the number of digits is 6. The first solution is to put all the balls in container 0, ie.
000000
The next solution is to put all the balls in container 0, excepted the last which goes in container 1.
000001
...
000002
000010
000011
000020
Hopefully you should get the idea.

Related

Adding numbers in a matrix

I have a two-dimensional array, and I want to sum all the values in that array, where the value is not -1.
Suppose I have a matrix that has the following values:
0,1 = 1.68
1,2 = 1.74
2,0 = 1.61
3,4 = -1
...
I want to add the all the numbers that are not -1
What I did try, and which obviously doesn't work for me, is:
for(i=0; i<data.length; ++i) {
for(j=0; j<data.length; ++j) {
if(data[i][j] != -1) {
sum += data[i][j]+data[j][i]
}
}
}
In my case, if an index (n, m) = k then it is also true that index (m, n) = k.
So for example, if (n, m) = 1.74, then (m, n) = 1.74. That is why I need to do data[i][j]+data[j][i] in the code above
What I REALLY want as result, is this: sum = (0,1 + 1,0) + (1,2 + 2,0) + (2,0 + 0,2) => sum = 2*(1,68) + 2*(1,74) + 2*(1,68)
What I get as result from my code above, is undefined.
I tried an alternative solution using .map (...), which according to the document, takes a function to map. But for now it is just a bit too complicated for me with the double array (I'm not experienced programmer yet)
data.map((a,i) => a.map((n,j) => n+data[i][j]));
I got an error here saying a not a function
You can use nested reduce
const data = [];
var dt = [1,2,3]
data[0] = dt;
data[1] = dt;
data[2] = dt;
var total = data.reduce((n,arr)=> n+arr.reduce((n,val)=>n+val), 0);
console.log(total);
I suppose that you want to sum all the values in a square matrix. So even though (m,n) = (n,m) in your matrix, one simple way to sum the values is :
let sum = 0;
for (let i = 0; i < data.length; i++) {
for (let j = 0; j < data.length; j++) {
if (data[i][j] !== -1) sum += data[i][j];
}
}
console.log(sum);
But if you want to do some calculation that take into account the fact that (m,n) = (n,m) in your matrix, you can try this:
let sum = 0;
for (let i = 0; i < data.length; i++) {
for (let j = 0; j < data.length; j++) {
if (data[i][j] !== -1) {
if (i === j) sum += data[i][j];
if (j < i) sum += 2*data[i][j];
}
}
}
console.log(sum);

Find all permutations of smaller string s in string b (JavaScript)

I've been trying to find a O(n) solution to the following problem: Find the number of anagrams (permutations) of string s in string b, where s.length will always be smaller than b.length
I read that the optimal solution involves keeping track of the frequencies of the characters in the smaller string and doing the same for the sliding window as it moves across the larger string, but I'm not sure how that implementation actually works. Right now my solution doesn't work (see comments) but even if it did, it would take O(s + sn) time.
EDIT: Sample input: ('aba', 'abaab'). Output: 3, because 'aba' exists in b starting at index 0, and 'baa' at 1, and 'aab' at 2.
function anagramsInStr(s,b) {
//O(s)
let freq = s.split("").reduce((map, el) => {
map[el] = (map[el] + 1) || 1;
return map;
}, {});
let i = 0, j = s.length;
// O(n)
for (let char in b.split("")) {
// O(s)
if (b.length - char + 1 > s.length) {
let window = b.slice(i,j);
let windowFreq = window.split("").reduce((map, el) => {
map[el] = (map[el] + 1) || 1;
return map;
}, {});
// Somewhere about here compare the frequencies of chars found in the window to the frequencies hash defined in the outer scope.
i++;
j++;
}
}
}
Read through the comments and let me know if you have any questions:
function countAnagramOccurrences(s, b) {
var matchCount = 0;
var sCounts = {}; // counts for the letters in s
var bCounts = {}; // counts for the letters in b
// construct sCounts
for (var i = 0; i < s.length; i++) {
sCounts[s[i]] = (sCounts[s[i]] || 0) + 1;
}
// all letters that occur in sCounts
var letters = Object.keys(sCounts);
// for each letter in b
for (var i = 0; i < b.length; i++) {
// maintain a sliding window
// if we already have s.length items in the counts, remove the oldest one
if (i >= s.length) {
bCounts[b[i-s.length]] -= 1;
}
// increment the count for the letter we're currently looking at
bCounts[b[i]] = (bCounts[b[i]] || 0) + 1;
// test for a match (b counts == s counts)
var match = true;
for (var j = 0; j < letters.length; j++) {
if (sCounts[letters[j]] !== bCounts[letters[j]]) {
match = false;
break;
}
}
if (match) {
matchCount += 1;
}
}
return matchCount;
}
console.log(countAnagramOccurrences('aba', 'abaab')); // 3
EDIT
A note about the runtime: this is sort of O(nk + m), where n is the length of s, m is the length of b, and k is the number of unique characters in b. Since m is always less than n, we can reduce to O(nk), and since k is bounded by a fixed constant (the size of the alphabet), we can further reduce to O(n).

Sum of Primes using Sieve of Eratosthenes can't find bug

I'm working in JavaScript and this is a bit confusing because the code is returning the correct sum of primes. It is working with larger numbers. There is a bug where for 977 it returns the sum of primes for 976, which is 72179, instead of the sum for 977 which is 73156. Everything I've test so far has come back correctly.
function sumPrimes(num) {
var sum = 0;
var count = 0;
var array = [];
var upperLimit = Math.sqrt(num);
var output = [];
for (var i = 0; i < num; i++) {
array.push(true);
}
for (var j = 2; j <= upperLimit; j++) {
if (array[j]) {
for (var h = j * j; h < num; h += j) {
array[h] = false;
}
}
}
for (var k = 2; k < num; k++) {
if (array[k]) {
output.push(k);
}
}
for (var a = 0; a < output.length; a++) {
sum += output[a];
count++;
}
return sum;
}
sumPrimes(977);
The problem stems from the fact that your "seive" Array is indexed from 0, but your algorithm assumes that array[n] represents the number n.
Since you want array[n]===true to mean that n is prime, you need an Array of length 978 if you want the last item to be indexed as array[977] and mean the number 977.
The issue seems to be fixed when I change all instances of < num to < num+1.

Find the multiple of n numbers within given range

How can I find the number of multiple for N numbers(as an array input) for a range 1 to K, where 1 < K < 10⁸ and 3 ≤ N < 25.
function findNumberOfMultiples(inputArray, maxSize) {
var count = 0;
var tempArray = [];
for (var i=0; i<maxSize; i++){
tempArray[i] = 0;
}
for (var j=0; j<inputArray.length; j++) {
for (var i=1; i<=maxSize; i++) {
if (i % inputArray[j]) {
tempArray[i-1] = 1;
}
}
}
for (var i=0; i<maxSize; i++) {
if (tempArray[i]==1) {
count++;
}
}
return count;
}
The above program fails for large number K. For example, if inputArray = [2,3,4] and maxSize(k) is 5,
Multiple of 2 is 2,4
Multiple of 3 is 3
multiple of 4 is 4
so total number of mutiple of 2 or 3 or 4 is 3 in range 1 to 5
You can solve this in O(N^2) where N is the number of elements in your array.
let us say you have two element in your array [a1,a2] and the range is K
your answer will be = >
K/a1 + K/a2 - K/lcm(a1,a2) // because you added them in both a1 and a2
So If you have a1,.....ax elements, your answer would be
K/a1+.....K/ax - K/lcm(ai,aj) (you have to replace i,j by (n*n-1)/2 combinations.
You will have to do K/lcm(ai,aj) O(N^2) times ((n*n-1)/2 time to be precise). So the algorithm complexity will be O(N^2) (There will be a Log(min(ai,aj)) factor but that would not make much difference to the overall complexity).
This will work any K as it only depends on your innput array size.
public int combinations(int K, int[] input){
int total = 0;
for(int i=0;i<input.length;i++){
total = total + Math.floor(K/input[i]);
}
for(int i=0;i<input.length;i++){
for(int j=i+1;j<input.length;j++){
if(i!=j){
int lcm =lcmFind(input[i], input[j]);
total = total - Math.floor(K/lcm);
}
}
}
return total;
}
The test case you have provided:
This function seems to do the trick :
var findMultiplesLength = function(arrayInput, max) {
var globalMultiples = [];
for (var j = 0; j < arrayInput.length; j++) {
var x = arrayInput[j];
var n = max / x;
for (var i=1; i < n; i++) {
mult = i * x;
if (globalMultiples.indexOf(mult) === -1) {
globalMultiples.push(mult);
}
}
}
return globalMultiples.length;
};
EDIT : You won't have any stack error but choosing big values for the range may hang your browser.

Variable amount of nested for loops

Edit: I'm sorry, but I forgot to mention that I'll need the values of the counter variables. So making one loop isn't a solution I'm afraid.
I'm not sure if this is possible at all, but I would like to do the following.
To a function, an array of numbers is passed. Each number is the upper limit of a for loop, for example, if the array is [2, 3, 5], the following code should be executed:
for(var a = 0; a < 2; a++) {
for(var b = 0; b < 3; b++) {
for(var c = 0; c < 5; c++) {
doSomething([a, b, c]);
}
}
}
So the amount of nested for loops is equal to the length of the array. Would there be any way to make this work? I was thinking of creating a piece of code which adds each for loop to a string, and then evaluates it through eval. I've read however that eval should not be one's first choice as it can have dangerous results too.
What technique might be appropriate here?
Recursion can solve this problem neatly:
function callManyTimes(maxIndices, func) {
doCallManyTimes(maxIndices, func, [], 0);
}
function doCallManyTimes(maxIndices, func, args, index) {
if (maxIndices.length == 0) {
func(args);
} else {
var rest = maxIndices.slice(1);
for (args[index] = 0; args[index] < maxIndices[0]; ++args[index]) {
doCallManyTimes(rest, func, args, index + 1);
}
}
}
Call it like this:
callManyTimes([2,3,5], doSomething);
Recursion is overkill here. You can use generators:
function* allPossibleCombinations(lengths) {
const n = lengths.length;
let indices = [];
for (let i = n; --i >= 0;) {
if (lengths[i] === 0) { return; }
if (lengths[i] !== (lengths[i] & 0x7fffffff)) { throw new Error(); }
indices[i] = 0;
}
while (true) {
yield indices;
// Increment indices.
++indices[n - 1];
for (let j = n; --j >= 0 && indices[j] === lengths[j];) {
if (j === 0) { return; }
indices[j] = 0;
++indices[j - 1];
}
}
}
for ([a, b, c] of allPossibleCombinations([3, 2, 2])) {
console.log(`${a}, ${b}, ${c}`);
}
The intuition here is that we keep a list of indices that are always less than the corresponding length.
The second loop handles carry. As when incrementing a decimal number 199, we go to (1, 9, 10), and then carry to get (1, 10, 0) and finally (2, 0, 0). If we don't have enough digits to carry into, we're done.
Set up an array of counters with the same length as the limit array. Use a single loop, and increment the last item in each iteration. When it reaches it's limit you restart it and increment the next item.
function loop(limits) {
var cnt = new Array(limits.length);
for (var i = 0; i < cnt.length; i++) cnt[i] = 0;
var pos;
do {
doSomething(cnt);
pos = cnt.length - 1;
cnt[pos]++;
while (pos >= 0 && cnt[pos] >= limits[pos]) {
cnt[pos] = 0;
pos--;
if (pos >= 0) cnt[pos]++;
}
} while (pos >= 0);
}
One solution that works without getting complicated programatically would be to take the integers and multiply them all. Since you're only nesting the ifs, and only the innermost one has functionality, this should work:
var product = 0;
for(var i = 0; i < array.length; i++){
product *= array[i];
}
for(var i = 0; i < product; i++){
doSomething();
}
Alternatively:
for(var i = 0; i < array.length; i++){
for(var j = 0; j < array[i]; j++){
doSomething();
}
}
Instead of thinking in terms of nested for loops, think about recursive function invocations. To do your iteration, you'd make the following decision (pseudo code):
if the list of counters is empty
then "doSomething()"
else
for (counter = 0 to first counter limit in the list)
recurse with the tail of the list
That might look something like this:
function forEachCounter(counters, fn) {
function impl(counters, curCount) {
if (counters.length === 0)
fn(curCount);
else {
var limit = counters[0];
curCount.push(0);
for (var i = 0; i < limit; ++i) {
curCount[curCount.length - 1] = i;
impl(counters.slice(1), curCount);
}
curCount.length--;
}
}
impl(counters, []);
}
You'd call the function with an argument that's your list of count limits, and an argument that's your function to execute for each effective count array (the "doSomething" part). The main function above does all the real work in an inner function. In that inner function, the first argument is the counter limit list, which will be "whittled down" as the function is called recursively. The second argument is used to hold the current set of counter values, so that "doSomething" can know that it's on an iteration corresponding to a particular list of actual counts.
Calling the function would look like this:
forEachCounter([4, 2, 5], function(c) { /* something */ });
This is my attempt at simplifying the non-recursive solution by Mike Samuel. I also add the ability to set a range (not just maximum) for every integer argument.
function everyPermutation(args, fn) {
var indices = args.map(a => a.min);
for (var j = args.length; j >= 0;) {
fn.apply(null, indices);
// go through indices from right to left setting them to 0
for (j = args.length; j--;) {
// until we find the last index not at max which we increment
if (indices[j] < args[j].max) {
++indices[j];
break;
}
indices[j] = args[j].min;
}
}
}
everyPermutation([
{min:4, max:6},
{min:2, max:3},
{min:0, max:1}
], function(a, b, c) {
console.log(a + ',' + b + ',' + c);
});
There's no difference between doing three loops of 2, 3, 5, and one loop of 30 (2*3*5).
function doLots (howMany, what) {
var amount = 0;
// Aggregate amount
for (var i=0; i<howMany.length;i++) {
amount *= howMany[i];
};
// Execute that many times.
while(i--) {
what();
};
}
Use:
doLots([2,3,5], doSomething);
You can use the greedy algorithm to enumerate all elements of the cartesian product 0:2 x 0:3 x 0:5. This algorithm is performed by my function greedy_backward below. I am not an expert in Javascript and maybe this function could be improved.
function greedy_backward(sizes, n) {
for (var G = [1], i = 0; i<sizes.length; i++) G[i+1] = G[i] * sizes[i];
if (n>=_.last(G)) throw new Error("n must be <" + _.last(G));
for (i = 0; i<sizes.length; i++) if (sizes[i]!=parseInt(sizes[i]) || sizes[i]<1){ throw new Error("sizes must be a vector of integers be >1"); };
for (var epsilon=[], i=0; i < sizes.length; i++) epsilon[i]=0;
while(n > 0){
var k = _.findIndex(G, function(x){ return n < x; }) - 1;
var e = (n/G[k])>>0;
epsilon[k] = e;
n = n-e*G[k];
}
return epsilon;
}
It enumerates the elements of the Cartesian product in the anti-lexicographic order (you will see the full enumeration in the doSomething example):
~ var sizes = [2, 3, 5];
~ greedy_backward(sizes,0);
0,0,0
~ greedy_backward(sizes,1);
1,0,0
~ greedy_backward(sizes,2);
0,1,0
~ greedy_backward(sizes,3);
1,1,0
~ greedy_backward(sizes,4);
0,2,0
~ greedy_backward(sizes,5);
1,2,0
This is a generalization of the binary representation (the case when sizes=[2,2,2,...]).
Example:
~ function doSomething(v){
for (var message = v[0], i = 1; i<v.length; i++) message = message + '-' + v[i].toString();
console.log(message);
}
~ doSomething(["a","b","c"])
a-b-c
~ for (var max = [1], i = 0; i<sizes.length; i++) max = max * sizes[i];
30
~ for(i=0; i<max; i++){
doSomething(greedy_backward(sizes,i));
}
0-0-0
1-0-0
0-1-0
1-1-0
0-2-0
1-2-0
0-0-1
1-0-1
0-1-1
1-1-1
0-2-1
1-2-1
0-0-2
1-0-2
0-1-2
1-1-2
0-2-2
1-2-2
0-0-3
1-0-3
0-1-3
1-1-3
0-2-3
1-2-3
0-0-4
1-0-4
0-1-4
1-1-4
0-2-4
1-2-4
If needed, the reverse operation is simple:
function greedy_forward(sizes, epsilon) {
if (sizes.length!=epsilon.length) throw new Error("sizes and epsilon must have the same length");
for (i = 0; i<sizes.length; i++) if (epsilon[i] <0 || epsilon[i] >= sizes[i]){ throw new Error("condition `0 <= epsilon[i] < sizes[i]` not fulfilled for all i"); };
for (var G = [1], i = 0; i<sizes.length-1; i++) G[i+1] = G[i] * sizes[i];
for (var n = 0, i = 0; i<sizes.length; i++) n += G[i] * epsilon[i];
return n;
}
Example :
~ epsilon = greedy_backward(sizes, 29)
1,2,4
~ greedy_forward(sizes, epsilon)
29
One could also use a generator for that:
function loop(...times) {
function* looper(times, prev = []) {
if(!times.length) {
yield prev;
return;
}
const [max, ...rest] = times;
for(let current = 0; current < max; current++) {
yield* looper(rest, [...prev, current]);
}
}
return looper(times);
}
That can then be used as:
for(const [j, k, l, m] of loop(1, 2, 3, 4)) {
//...
}

Categories