Excuse me, quick question:
I am using the below routine to find all Combinations of integers that their sum is equal or less than some integer K.
Imagine I have a glass with volume K, and some beer bottles. I am trying to know which bottles I can pick, and get as much beer as possible!
let K = 4; // my glass
let Input = [1, 2, 0.5, 1.5, 2, 0.75, 3, 4]; // beer bottles
let allCombinations = [];
for(var i = 0; i < Input.length; i++)
{
let currentCombination = [];
if(Input[i] <= K)
currentCombination.push(Input[i]);
let difference = K - Input[i];
for(var j = i + 1; j < Input.length; j++)
{
if(Input[j] <= difference)
{
currentCombination.push(Input[j]);
difference -= Input[j];
}
}
allCombinations.push(currentCombination);
}
Input:
K = 4
[1, 2, 0.5, 1.5, 2, 0.75, 3, 4]
Current Output:
[1, 2, 0.5]
[2, 0.5, 1.5]
[0.5, 1.5, 2]
[1.5, 2]
[2, 0.75]
[0.75, 3]
[3]
[4]
But I want more beer choices! Some combinations are not included:
Expected Output:
All the above, plus:
[1, 2, 1.5]
[1, 2, 0.75]
[2, 0.5, 0.75]
[2, 2]
[1, 3]
etc ..
My guess is that this is suboptimal, but you could use a recursive algorithm that produces all possible permutations, checks each one to determine if it's a unique combination, and adds unique solutions to a solution list:
combinations = [];
function getCombinationsLessThan(currentCombination, choices, remainingSum) {
// Check if currentCombination should be added to the solutions list
if (remainingSum < 0) {
return // Sum is too large; terminate recursion
} else if (currentCombination.length > 0) {
currentCombination.sort(); // Sort all combinations so comparison can be made sequentially
var uniquePermutation = true;
for (var i=0; i<combinations.length; i++) {
if (currentCombination.length == combinations[i].length) {
for (var j=0; currentCombination[j]==combinations[i][j] && j<combinations[i].length; j++); // Pass
if (j == currentCombination.length) {
// For loop got all the way through combinations[i], so currentCombination = combinations[i]
uniquePermutation = false;
break;
}
}
}
if (uniquePermutation) {
combinations.push(currentCombination);
}
}
for (var i=0; i<choices.length; i++) {
// Copy choices
var newChoices = choices.slice();
// Cut out the i'th element and add to the current combination
var newCombination = currentCombination.concat(newChoices.splice(i,1));
var newRemainingSum = remainingSum - choices[i];
getCombinationsLessThan(newCombination, newChoices, newRemainingSum);
}
}
var k = 4;
var choices = [1, 2, 0.5, 1.5, 2, 0.75, 3, 4];
getCombinationsLessThan([], choices, k);
var result = '';
for (var i=0; i<combinations.length; i++) {
result += combinations[i] + '\n';
}
console.log(result);
This produces the following result:
1
1,2
0.5,1,2
0.75,1,2
0.5,1
0.5,1,1.5
0.5,0.75,1,1.5
0.5,0.75,1
1,1.5
0.75,1,1.5
0.75,1
1,3
2
0.5,2
0.5,1.5,2
0.5,0.75,2
1.5,2
2,2
0.75,2
0.5
0.5,1.5
0.5,0.75,1.5
0.5,0.75
0.5,3
1.5
0.75,1.5
0.75
0.75,3
3
4
I agree. This does sound like the knapsack problem: determine if excluding or including an item in the knapsack results in a higher value that does not exceed the capacity of the container.
Related
I'm doing the following codesignal:
Each of the rooms has a different cost, and some of them are free, but there's a rumour that all the free rooms are haunted! Since the CodeBots are quite superstitious, they refuse to stay in any of the free rooms, or any of the rooms below any of the free rooms.
Given matrix, a rectangular matrix of integers, where each value represents the cost of the room, your task is to return the total sum of all rooms that are suitable for the CodeBots (ie: add up all the values that don't appear below a 0).
Example
For
matrix = [[0, 1, 1, 2],
[0, 5, 0, 0],
[2, 0, 3, 3]]
the output should be
solution(matrix) = 9.
This is what I came up with, but it's not passing.
function solution(matrix) {
let rooms = []
for (let i = 0; i < matrix.length; i++) {
if (matrix[i] !== 0 || matrix[i-4] !== 0) {
rooms.push(i)
}
}
rooms.reduce((a, b) => a + b, 0)
}
I think it's not passing because its three small arrays in one large one. So is there a way to easily combine the three small arrays into one large one, then I can loop over it and run the conditional?
You don't need to convert to 1d array as it will be extra work, instead you solve it as follows:
you need to check whether the item above the one you are currently at is 0 or not. The item above any item in a 2d array is at index [i-1][j] where i is your current item. Make sure at i = 0 you directly add the item to the array to avoid getting index out of bounds exception.
This is my code:
let matrix = [[0, 1, 1, 2],
[0, 5, 0, 0],
[2, 0, 3, 3]];
let sum = 0;
for(i = 0; i < matrix.length; i++) {
for(j = 0; j < matrix[i].length; j++) {
if(i === 0) {
sum += matrix[i][j];
continue;
}
if(i - 1 < 0) continue;
if(matrix[i - 1][j] !== 0) sum += matrix[i][j];
}
}
console.log(sum)
Loop over rows & columns, when 0 is found, sum 0 for that and further values in that column:
const matrix = [
[0, 1, 1, 2],
[0, 5, 0, 0],
[2, 0, 3, 3]
];
function solution (matrix) {
let skip = {}, sum = 0;
for (const a of matrix)
for (let i = 0; i < a.length; i++)
sum += skip[i] || (skip[i] = !a[i]) ? 0 : a[i];
return sum;
};
console.log(solution(matrix));
Basically I have an array where there are similar items close by, but I would like to find a way where I leave these items that are the same apart from each other ex:
var array = [1,2,3,3,4];
var myWishArray = [1,2,3,4,3];
||
var myWishArray = [3,2,3,4,1];
||
var myWishArray = [3,2,3,1,4];
...
If it's enough that two equal numbers are never neighbors, then you can
sort the list
fill a new array with these numbers in two passes, leaving a space of one
a = [1, 1, 1, 1, 2, 3, 2, 3, 4, 4, 4];
a.sort();
b = Array(a.length);
for (i = 0; i < a.length; i ++) {
if (i * 2 < a.length) {
b[i * 2] = a[i];
} else {
start = i - Math.ceil(a.length / 2)
b[start * 2 + 1] = a[i];
}
}
console.log(b);
My question is closely related to this question but I'm looking for a solution in Javascript
How to Transpose 2D Matrix Stored as C 1D Array
Basically I have a 2D square matrix
1 2 3
4 5 6
7 8 9
Stored as follows
let anArray = [1 ,2, 3, 4, 5, 6, 7, 8, 9]
How can I transpose this matrix so that the elements of my source array are switched as follows?
let newArray = [1, 4, 7, 2, 5, 8, 3, 6, 9]
You could take the length for the dimension of the array and map items on a specific index for a new array.
var array = [1 ,2, 3, 4, 5, 6, 7, 8, 9],
n = Math.sqrt(array.length),
transposed = array.map((_, i, a) => a[(i % n) * n + Math.floor(i / n)]);
console.log(transposed.join(' '));
The approach in the answer you linked to works well in JavaScript too.
For a 3 x 3:
const anArray = [1, 2, 3, 4, 5, 6, 7, 8, 9];
let newArray = [];
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
newArray[3 * i + j] = anArray[3 * j + i];
}
}
console.log(newArray);
For an N x N, just replace the 3's with N.
This answer avoids division and flooring (integer division) and a decent optimizer should make the code relatively fast. You might also consider initializing the new array with
let newArray = new Array(9);
or
let newArray = new Array(N * N);
but profile the code before attempting "optimizations" such as this.
var arr1 = [];
var arr2 = [];
for(int i=0; i<mat.length; i++) {
for(int j=0; j<mat[i].length; j++) {
arr1.push(mat[i][j]);
}
}
for(int j=0; j<mat[i].length; j++) {
for(int i=0; i<mat.length; i++) {
arr2.push(mat[i][j]);
}
}
Set a max "width" for your matrix and insert into a new array in loops, offset by 1 for each run.
function transpose(list, width) {
if (width === void 0) {
width = 1;
}
var t = 0;
var transposed = [];
while (t < width) {
for (var index = t; index < list.length; index += width) {
transposed.push(list[index]);
}
t++;
}
return transposed;
}
//TEST
var list = [1, 2, 3, 4, 5, 6, 7, 8, 9];
var transposed = transpose(list, 3);
console.log(list.join());
console.log(transposed.join());
This question already has answers here:
Permutations in JavaScript?
(41 answers)
Closed 6 years ago.
I have different arrays, all with numbers, but with different number of elements:
var ar1 = [2, 5];
var ar2 = [1, 2, 3];
I need to get all permutations for each array. The length of the output elements should always be the same as the input array.
This result should be an array of arrays, like this:
for ar1:
[2, 5]
[5, 2]
for ar2:
[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
[2, 3, 1]
[3, 1, 2]
[3, 2, 1]
I don't want a cartesian product, each array should be processed on its own.
All solutions I found so far are creating only order independent arrays, so the result for ar1 is only one array and not two.
The Solution should work for any number of elements in the input array. We can assume that there are no duplicate values in the input array.
You could use for a permutation an iterative and recursive approach until not more elements are to distribute.
function permutation(array) {
function p(array, temp) {
var i, x;
if (!array.length) {
result.push(temp);
}
for (i = 0; i < array.length; i++) {
x = array.splice(i, 1)[0];
p(array, temp.concat(x));
array.splice(i, 0, x);
}
}
var result = [];
p(array, []);
return result;
}
console.log('something bigger [1,2,3,4,5,6,7]');
console.time('t1');
permutation([1, 2, 3, 4, 5, 6, 7]);
console.timeEnd('t1');
console.log(permutation([2, 5]));
console.log(permutation([1, 2, 3]));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Not sure if this is the best way, but it seems to work.
#Nina's solution looks good, but it does a fair bit of array concat & slice, so this might work better for larger sets as it avoids that. I do use an object for duplicate checking, but hashmaps are super fast in JS.
Just curious, so did a performance test.
Doing [1,2,3,4,5,6,7], using #Nina's solution take's 38.8 seconds,.
Doing mine toke 175ms.. So the array concat / slice is a massive performance hit, and the marked duplicate will have the same issue. Just something to be aware off.
var ar1 = [2, 5];
var ar2 = [1, 2, 3];
function combo(c) {
var r = [],
len = c.length;
tmp = [];
function nodup() {
var got = {};
for (var l = 0; l < tmp.length; l++) {
if (got[tmp[l]]) return false;
got[tmp[l]] = true;
}
return true;
}
function iter(col,done) {
var l, rr;
if (col === len) {
if (nodup()) {
rr = [];
for (l = 0; l < tmp.length; l++)
rr.push(c[tmp[l]]);
r.push(rr);
}
} else {
for (l = 0; l < len; l ++) {
tmp[col] = l;
iter(col +1);
}
}
}
iter(0);
return r;
}
console.log(JSON.stringify(combo(ar1)));
console.log(JSON.stringify(combo(ar2)));
console.log('something bigger [1,2,3,4,5,6,7]');
console.time('t1');
combo([1,2,3,4,5,6,7]);
console.timeEnd('t1');
Lets assume we have an array of those elements (always sorted).
[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3]
Our goal is to find the min-index and max-index of a given value e.g. Lets assume we're searching for the min-index and max-index of the element 3.
We quickly see, that the min-index for 3 is 8 and the max-index is 11.
For the value 1, the min is 0 and the max is 3.
How would you develop a solution for that returns the min and max in JavaScript? I have tried to do this, but I can't figure how to, I always get the wrong answer.
You can try Array.indexOf() and Array.lastIndexOf()
var sortedArr =[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3];
console.log(sortedArr.indexOf(1));
console.log(sortedArr.lastIndexOf(1));
Basically Array.indexOf() and Array.lastIndexOf() will do it but they'll do a linear search (go through whole array with a loop until the element is found) which is obviously done in linear time O(n).
If it is true that your array is always sorted then we can use this property to optimize it and use binary search. It is way faster and will do it in logarithmic time O(log n).
After that we simply check the elements before (and after) the found index and until we find an element which isn't equal to our element.
For finding last occurence:
var i= foundIndex;
while(sortedArr[i] == sortedArr[foundIndex]){
i++;
}
foundIndex = i;
And for first occurence:
var i= foundIndex;
while(sortedArr[i] == sortedArr[foundIndex]){
i--;
}
foundIndex = i;
That's it! This will help a lot with the run time especially if you have big arrays.
You can find binary search implementations everywhere, just use any of them.
Is that what you want?
var myarr = [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3];
var minNum = myarr[0];
var maxNum = myarr[1];
var minNumStartINDX, maxNumStartINDX, minNumEndINDX, maxNumEndINDX;
/********************************************/
for (var x = 0; x < myarr.length; ++x) {
if (minNum >= myarr[x]) {
minNum = myarr[x];
minNumEndINDX = x;
}
}
for (var x = 0; x < myarr.length; ++x) {
if (minNum >= myarr[x]) {
minNumStartINDX = x;
break;
}
}
for (var x = 0; x < myarr.length; ++x) {
if (maxNum <= myarr[x]) {
maxNum = myarr[x];
maxNumEndINDX = x;
}
}
for (var x = 0; x < myarr.length; ++x) {
if (maxNum <= myarr[x]) {
maxNumStartINDX = x;
break;
}
}
/********************************************/
console.log(minNum);
console.log(minNumStartINDX + "-" + minNumEndINDX);
console.log(maxNum);
console.log(maxNumStartINDX + "-" + maxNumEndINDX);
var data={1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3};
var value=3;
var min=data.length;
var max=0;
for(var key in data){
if(data[key]==value){
if(key<min){
min=key;
}
if(key > max){
max=key;
}
}
console.log(min);
console.log(max);