I am trying to solve a leetcode type problem that is a practice problem that came with an upcoming code test I need to do for a job and I am having trouble with it. Can anyone help me understand whats going wrong?
I am essentially looking for the brute force option as I dont know algos/DS.
PROBLEM:
Write a function:
function solution(A);
that, given an array A of N integers, returns the smallest positive integer (greater than 0) that does not occur in A.
For example, given A = [1, 3, 6, 4, 1, 2], the function should return 5.
Given A = [1, 2, 3], the function should return 4.
Given A = [−1, −3], the function should return 1.
Write an efficient algorithm for the following assumptions:
N is an integer within the range [1..100,000];
each element of array A is an integer within the range [−1,000,000..1,000,000].
HERE IS MY SOLUTION:
function solution(A) {
let newArray = A.sort(function(a, b){return a-b})
let lowestNumber = 1
for(i=0; i < newArray.length; i++) {
if(lowestNumber > newArray[0]) {
return lowestNumber
}
if(lowestNumber == newArray[i]) {
lowestNumber = lowestNumber + 1
}
if(i = newArray.length - 1) {
return lowestNumber
}
}
}
The below snippet isnt working like I expect it to. lowestNumber isnt being increased and also the loop is exiting here I believe.
if(lowestNumber == newArray[i]) {
lowestNumber = lowestNumber + 1
Thanks for your help!
You can do this in O(N) using a Map():
First set every number in the array.
Then starting from 1 look for and return the missing number in the sequence.
function solution(arr) {
const seen = new Map();
for (let i = 0; i < arr.length; i++) {
seen.set(arr[i]);
}
for (let i = 1; i <= arr.length + 1; i++) {
if (!seen.has(i)) return i;
}
return 1;
}
console.log(solution([1, 3, 6, 4, 1, 2])); //-> 5
console.log(solution([1, 2, 3])); //-> 4
console.log(solution([-1, -3])); //-> 1
I think your > should be <, and the = in if(i = newArray.length - 1) should be ===.
And lowestNumber > newArray[0] will always be true if the array contains a negative number, so 1 will be returned.
Your effort seems careless, so you are going to have to up your game for the interview.
const integers = [5, -345, 562456, 95345, 4, 232, 1, 2, 3, 7, -457];
function solution(A) {
let newArray = A.sort((a, b) => a - b);
let lowestNumber = 1;
for (let i = 0; i < newArray.length; i++) {
const n = newArray[i];
if (n > 0) {
if (lowestNumber < n) {
return lowestNumber;
} else {
lowestNumber = n + 1;
}
}
}
return lowestNumber;
}
console.log(solution(integers));
The fastest solution
function solution(A) {
// write your code in JavaScript (Node.js 8.9.4)
if (!A) return 1;
A.sort();
if (A[A.length - 1] < 1) return 1;
const setA = new Set(A);
let length = setA.size;
for (let i = 1; i <= length; i++) {
if (!setA.has(i)) {
return i;
}
}
return length + 1;
}
I have worked same problem for nowadays, and regardless the original answer, here is my version of finding least positive number which is missing the in the array.
function findLeastPositive(array) {
const numbersSet = new Set(array);
let leastPositiveNumber = 1;
while(numbersSet.has(leastPositiveNumber)) {
leastPositiveNumber++;
}
return leastPositiveNumber;
}
let result = findLeastPositive([1,2,3,4,5,6,7,8,9,0]);
console.log(result);
result = findLeastPositive([10,11,12,13,14,15,16,17,18,19]);
console.log(result);
There are sure similar answers floating on the internet but using given array length disturbing me of which I can't explain properly why we have to create second loop starts with 1 (known the least positive number) and to N.
Using hash table (I am using Set here) for lookup table is fine idea, as in it effect to overall performance O(N) (probably initialize the Set with array) and O(1) for checking if the value in the Set or not.
Then we need to set second loop for obvious reason that checking the the smallest positive number existence, starting from 1..N range. This is the part bugged me, so I decided to go for while loop. It's obvious rather why there's a for..loop starts from 1..N on which N is the length of the array.
Here is 100% code
function solution(A) {
/**
* create new array of positive numbers in given array,
* if there sis no specific number in given array, in result array
* that index will be undefine
*/
const c = A.reduce((arr, cur) => {
if(cur > 0) arr[cur] = 1;
return arr;
} , [1] )
/**
* return first undefined index
*/
for(let i = 0; i < c.length; i++)
if(!c[i]) return i;
// otherwise return the maximum index in array
return c.length;
}
function solution(arr) {
for (let i = 1; i <= arr.length + 1; i++) {
if (!arr.includes(i)) return i;
}
return 1;
}
console.log(solution([1, 3, 6, 4, 1, 2])); //-> 5
console.log(solution([1, 2, 3])); //-> 4
console.log(solution([-1, -3])); //-> 1
Related
I have implemented solution in javascript using two loops, below is the code
function getNums(arr){
var res = [];
var found = {};
var i, j;
var arrLen = arr.length;
for(i=0; i<arrLen; i++){
if(!found.hasOwnProperty(arr[i])){
for(j=0; j<arrLen; j++){
if(arr[i]+arr[j] === 0){
var num = arr[i];
if(num > 0){
res.push(num);
found[num] = 1;
}
}
}
}
}
return res;
}
console.log(getNums[-1, -2, 0, -4, 1, 4, 6]); // Output: [1, 4]
Whose time complexity is O(n2). Can someone suggest better solution / refined above to have less complexity?
You can just add the array to a Set and filter for inclusion in the set. Determining if something is in a set is constant time:
let arr = [-1, 2, 3, 1 , 3, -3, 4, -6]
let s = new Set(arr)
// all positive numbers with corresponding negatives in the set
let filtered = arr.filter(item => item > 0 && s.has(-1 * item))
console.log(filtered)
An alternative is to sort the array and then walk two pointers up the array as making matches along the way. The result will be sorted, however, which may not be the same order as the original array:
let arr = [-2, -3, 2, 5, 3, 1, -6, 2, -5]
arr.sort()
// get startig indexes
let i = 0, j = arr.findIndex(n => n > 0)
let res = []
if (j > -1) { // only if there are positive numbers in the array
while(arr[i] < 0 && j < arr.length){
if (-1 * arr[i] === arr[j]){
res.push(arr[j++])
} else if(-1 * arr[i] > arr[j]){
j++
} else if(-1 * arr[i] < arr[j]){
i++
}
}
}
console.log(res)
You could take a single loop approach by counting the values.
function getNums(array) {
var count = Object.create(null),
result = [];
array.forEach(v => {
if (count[-v]) {
result.push(Math.abs(v));
count[-v]--;
return;
}
count[v] = (count[v] || 0) + 1;
});
return result;
}
console.log(getNums([1, 2, -3, -4, 2, 3, 4, 4, -4]));
Before the downvotes... This answer is not the shortest javascript code, but the algorithm - I think it is what the original question was about.
One way to get rid of nested loops is to use more memory to store intermediate structures. In your case, you want to store not just the "found" flag, but negative, positive values as well, so that at every iteration you can set the found flag. Then you also use the "found" flag to prevent adding the results 2nd time.
var f = function(arr) {
let hash = {};
let res = [];
for (var i = 0; i < arr.length; i++) {
// put value into the hash map for future use
hash[arr[i]] = arr[i];
var absVal = Math.abs(arr[i]);
// if value is not 0 AND if it has not been found yet (x+value hash) AND if both negative and positive values are present
if( arr[i] !== 0 && !hash["x"+absVal] && (hash[arr[i]] + hash[-arr[i]] === 0)){
// then set the found hash to true
hash["x"+absVal] = true;
// and push to the resut
res.push(absVal);
}
}
// return the result
return res;
}
Another solution is to use filter and includes prototype functions which are well optimized.
const getNums = (arr) => arr.filter((num, index) => num > 0 && !arr.includes(num, index + 1) && arr.includes(-num));
So, I was working on this challenge to return the third largest number in an array. I had got it worked out until I realized that I must account for repeat numbers. I handled this by adding 3 layers of for loops with variables i, j, and k. You'll see what I mean in the code. This is not terribly efficient or scalable.
My question is, how can I optimize this code? What other methods should I be using?
function thirdGreatest (arr) {
arr.sort(function(a, b) {
if (a < b) {
return 1;
} else if (a > b) {
return -1;
} else {
return 0;
}
});
for ( var i = 0; i < arr.length; i++) {
for (var j = 1; j < arr.length; j++) {
for (var k = 2; k < arr.length; k++) {
if (arr[i] > arr[j]) {
if (arr[j] > arr[k]) {
return arr[k];
}
}
}
}
}
}
console.log(thirdGreatest([5, 3, 23, 7,3,2,5,10,24,2,31, 31, 31])); // 23
console.log(thirdGreatest([5, 3, 23, 7,3,2,5,10,24,2,31])) // 23
console.log(thirdGreatest([5, 3, 7, 4])); // 4
console.log(thirdGreatest([2, 3, 7, 4])); // 3
Since you already sorted the array, it seems like you should be fine iterating over the list and keep track of the numbers you have already seen. When you have seen three different numbers, return the current one:
var seen = [arr[0]];
for (var i = 1; i < arr.length; i++) {
if (arr[i] !== seen[0]) {
if (seen.length === 2) {
return arr[i];
}
seen.unshift(arr[i]);
}
}
function thirdGreatest (arr) {
arr.sort(function(a, b) {
return b - a;
});
var seen = [arr[0]];
for (var i = 1; i < arr.length; i++) {
if (arr[i] !== seen[0]) {
if (seen.length === 2) {
return arr[i];
}
seen.unshift(arr[i]);
}
}
}
console.log(thirdGreatest([5, 3, 23, 7,3,2,5,10,24,2,31, 31, 31])); // 23
console.log(thirdGreatest([5, 3, 23, 7,3,2,5,10,24,2,31])) // 23
console.log(thirdGreatest([5, 3, 7, 4])); // 4
console.log(thirdGreatest([2, 3, 7, 4])); // 3
Note: You can simplify the sort callback to
arr.sort(function(a, b) {
return b - a;
});
// With arrow functions:
// arr.sort((a, b) => b - a);
The callback has to return a number that is larger, smaller or equal to 0, it doesn't have to be exactly -1 or 1.
A one-"line"r using Set to remove duplicates
Array.from(new Set(arr)).sort(function(a, b) {
return b - a;
})[2];
Set now has reasonable browser support
The optimal solution is to do this in a single pass O(n) time. You do not need to sort the array - doing so makes your solution at-least (n log n).
To do this in as single pass, you simply need three temporary variables: largest, secondLargest, thirdLargest. Just go through the array and update these values as necessary (i.e. when you replace largest it becomes second largest, etc...). Lastly, when you see duplicates (i.e. currentValue == secondLargest), just ignore them. They don't affect the outcome.
Don't forget to check for edge cases. You cannot provide an answer for [2, 2, 2, 2, 2] or [3, 2].
Try to think about what data structure you can use here. I suggest a set. Every time you add a nested loop your function gets exponentially slower.
Edited:
function thirdGreatest(arr) {
var s = Array.from(new Set(arr)).sort(function(a, b) {
return a - b;
})
return s[2] || s[1] || s[0] || null;
}
Working Example
We need to be able to handle:
[1,2,1,2] // 2
[1,1,1,1] // 1
[] // null
This assumes that you get an array passed in.
If you do not have a third largest number, you get the second.
If you do not have a second largest you get the first largest.
If you have no numbers you get null
If you want the 3rd largest or nothing, return s[2] || null
Many of the other answers require looping through the initial array multiple times. The following sorts and deduplicates at the same time. It's a little less terse, but is more performant.
const inputArray = [5,3,23,24,5,7,3,2,5,10,24,2,31,31,31];
const getThirdGreatest = inputArray => {
const sorted = [inputArray[0]]; // Add the first value from the input to sorted, for our for loop can be normalized.
let migrated = false;
let j;
for(let i = 1; i<inputArray.length; i++) { // Start at 1 to skip the first value in the input array
for(j=0; j<sorted.length; j++) {
if(sorted[j] < inputArray[i]) {
// If the input value is greater than that in the sorted array, add that value to the start of the sorted array
sorted.splice(j,0,inputArray[i]);
migrated = true;
break;
} else if(sorted[j] === inputArray[i]) {
// If the input value is a duplicate, ignore it
migrated = true;
break;
}
}
if(migrated === false) {
// If the input value wasn't addressed in the loop, add it to the end of the sorted array.
sorted[sorted.length] = inputArray[i];
} else {
migrated = false;
}
}
// Return the third greatest
return sorted[2];;
};
const start = performance.now();
getThirdGreatest(inputArray); // 23
const end = performance.now();
console.log('speed: ', end - start); // 0.1 - 0.2ms
One single iteration O(n) and very fast method of doing this is making your own Set like object. The advantageous point is making no comparisons at all when constructing our "sorted" list of "unique" elements which brings enormous efficiency. The difference is very noticeable when dealt with huge lists like in the lengths exceeding 1,000,000.
var arr = [5, 3, 23, 7,3,2,5,10,24,2,31, 31, 31],
sorted = Object.keys(arr.reduce((p,c)=> (p[c] = c, p),Object.create(null))),
third = sorted[sorted.length-3];
document.write(third);
If you think Object.keys might not return a sorted array (which i haven't yet seen not) then you can just sort it like it's done in the Set method.
Here i tried it for 1,000,000 item array and returns always with the correct result in around 45msecs. A 10,000,000 item array would take like ~450msec which is 50% less than other O(n) solutions listed under this question.
var arr = [],
sorted = [],
t0 = 0,
t1 = 0,
third = 0;
for (var i = 0; i<1000000; i++) arr[i] = Math.floor(Math.random()*100);
t0 = performance.now();
sorted = Object.keys(arr.reduce((p,c)=> (p[c] = c, p),Object.create(null)));
third = sorted[sorted.length-3];
t1 = performance.now();
document.write(arr.length + " size array done in: " + (t1-t0) + "msecs and the third biggest item is " + third);
I wish to execute a program with output as :
console.log(range(1, 10));
// → [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
console.log(range(5, 2, -1));
// → [5, 4, 3, 2]
console.log(sum(range(1, 10)));
// → 55
I am getting an error for array.length.Please find the code below:
var array = [];
function range (arr){
var lower = Math.min(arr[0],arr[1]);
var upper = Math.max(arr[0],arr[1]);
for (var i=lower;i<=upper;i++){
array.push(i);
}
}
function sum(array){
for(var i=0;i < array.length;i++){
var total = total+array[i];
}
}
console.log(sum(range(1, 10)));
I am at begineers level, please do help.
Thanks.
You have a few problems here:
1.) You aren't returning anything in your range function. You need to return the filled array.
2.) You aren't passing the array correctly in the sum function call.
3.) You aren't returning anything in your sum function call.
Without returning any values, you aren't letting your code blocks work with eachother
var array = [];
function range (arr){
var lower = Math.min(arr[0],arr[1]);
var upper = Math.max(arr[0],arr[1]);
for (var i=lower;i<=upper;i++){
array.push(i);
}
return array; // return the array to be used in the sum function
}
function sum(array){
var total = 0; // need to create a variable outside the loop scope
for(var i in array){
total = total+array[i];
}
return total;
}
console.log(sum(range([1,10]))); // pass the array correctly
Note that you need to set the total variable outside the scope of the for-loop within the sum function. That way you can return the final value. Otherwise, it would return undefined.
See the fiddle: https://jsfiddle.net/udyhb95a/
You need to pass an array when calling the range function you defined range([1, 10])
You need to rewrite your sum function
As a side note, there are more efficient ways to compute the sum of a range of elements without iterating on them.
function sum_of_range(start, end) {
return end * (end + 1) / 2 - start * (start + 1) / 2;
}
Edit:
Here is a working sum function
function sum(array) {
var accumulator = 0;
for (var i = 0; i < array.length; ++i)
accumulator += array[i];
return accumulator;
}
Here you declare a function with one parameter as an array
function range (arr){
...
But here you call a function with two arguments as numbers
console.log(range(1, 10));
Use this call function
console.log(range([1, 10]));
And don't use for..in for arrays
for(var i in array){ it doesn't work as you expect
Use forEach function or plan for loop
Also you have some error in sum function
See working example below:
function range(arr) {
var array = [];
var lower = Math.min(arr[0], arr[1]);
var upper = Math.max(arr[0], arr[1]);
for (var i = lower; i <= upper; i++) {
array.push(i);
}
return array;
}
function sum(array) {
var total = 0;
for (var i = 0; i < array.length; i++) {
total = total + array[i];
}
return total;
}
document.write('range ' + range([1, 10]) + '<br>');
document.write('sum ' + sum(range([1, 10])));
You need to modify sum & range function
function range (){
var array = [];
var lower = Math.min.apply(null, arguments);
var upper = Math.max.apply(null, arguments);
for (var i=lower;i<=upper;i++){
array.push(i);
}
return array;
}
function sum(array){
return array.reduce((x,y)=>x+y,0);
}
console.log(range(1, 10));
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
console.log(range(5, 2, -1)); //if we are considering min & max from params
// [-1, 0, 1, 2, 3, 4, 5]
console.log(sum(range(1, 10)));
// 55
Hello Dear check it now.
var array = [];
function range(arr, arr1) {
var lower = Math.min(arr);
var upper = Math.max(arr1);
for (var i = lower; i <= upper; i++) {
array.push(i);
}
}
function sum() {
var total = 0;
for (var i = 0; i < array.length; i++) {
total = total + array[i];
}
return total;
}
console.log(sum(range(1, 10)));
This is the correct answer to the problem at the end of the data structures chapter within Eloquent JavaScript
function range(start, end, step) {
let arr = []; //declare an empty array
var step = step || 1;//tests to see if step was supplied, otherwise it's 1
if(start < end)
{
for(let i = start; i <= end; i += step)
{
arr.push(i);
}
}
else
{
for(let i = start; i >= end; i += step)
{
arr.push(i);
}
}
return arr;
}
function sum(array) {
let total = 0;
for(let i = 0; i < array.length; i++)
{
total += array[i];
}
return total;
}
console.log(range(1, 10));
// → [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
console.log(range(5, 2, -1));
// → [5, 4, 3, 2]
console.log(sum(range(1,10)));
// → 55
This solution takes into account of entering a step that isn't expected to be positive/negative, i.e range from 1 to 5, we would expect step to be positive, but if the user somehow entered a negative step then an empty array would occur.
The browser actually hangs for the opposite, if the array is expected to decrease, but the step sizes are > 0.
'use strict';
function range(start, end, step = 1){
let output = [];
if (start > end){
// Sanity check, all steps if expected to go down should be negative
if (step > 0){
step = -step;
}
for (;start >= end; start += step){
console.log(start);
output.push(start);
}
}
else{
// Likewise, as all steps should be positive
if (step < 0){
step = -step;
}
for (;start <= end; start += step){
output.push(start);
}
}
return output;
}
function sum(arr){
let output = 0;
for (let i of arr){
output += i;
}
return output;
}
console.log(range(1, 5, 1));
// → [1, 2, 3, 4, 5]
console.log(range(5, 1, -1));
// → [5, 4, 3, 2, 1]
// Notice this one step is a positive, but this is handled (original solution returned empty array)
console.log(range(5, 1, 1));
// → [5, 4, 3, 2, 1]
console.log(sum(range(1,10)));
// → 55
An improvement onto this is to use the reduce function for an array to sum instead of a for loop, i.e:
function sum(array){
return array.reduce((x,y)=>x+y,0);
}
For people finding this later on as I did, here is a way to write the range function so you can pass the input as written in the original question:
console.log(sum(range(1, 10)));
…and a cleaned up sum function similar to the one in A. Sharma's answer:
function range(lower, upper) {
let array = []
for (let i = lower; i <= upper; i++) {
array.push(i);
}
return array;
}
function sum(array) {
let total = 0;
for (let i in array) {
total = total + array[i];
}
return total;
}
console.log(sum(range(1, 10)));
Also worth mentioning:
The use of reduce in JagsSparrow's answer, which is elegant, while not entirely obvious and newcomer friendly as Mathias Vonende pointed out.
Negative step tolerant versions in answers from Jimmy Wei and user3225968.
This is the best solution I've got
function range(x,y){
var arr = [];
for(x;x<=y;x++){
arr.push(x);
};
return arr;
};
function sum(array){
return array.reduce((a,b) => a + b, 0);
};
console.log(sum(range(1,10)));
This answer is quite late but I am learning these things now and want to share my solution. I have not seen this solution provided for the specific question "Sum of a range in Javascript" so I wanted to share it. What I have done here is made use of the pop method for the array which allowed me not to specifically pass an array argument to the range function but to provide a solution to the argument in the way it was originally presented in the question.
var result = [];
var counter = 0;
function range(start, end) {
for (let i = start; i <= end; i++) {
result.push(i);
}
return result;
}
function sum(array) {
for (let i = 0; i < result.length; i++) {
counter += result.pop(i);
}
return counter;
}
console.log(range(1, 10));
// → [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
console.log(sum(range(1, 10)));
// → 55
This can be accomplished very easily and efficiently without any globally scoped vars.
It's not clear in the original question what behavior should be applied to the -1 argument. It seems to be an indicator to reverse the range. In the below example, I've used a boolean to check this argument. A value of -1 would actually be the same as not providing a third argument. To reverse the range, pass in any truthy value.
function range(from, to, reverse) {
// Make sure our inputs are actually numbers
if (Number(from) != from || Number(to) != to) {
throw new TypeError("range() expects a Number as both it's first and second argument");
}
let o = []; // initialize our output array
// get the lowest value argument as our starting index
let i = Math.min(from, to);
// get the highest value argument as our ending index
let x = Math.max(from, to);
// push i onto our output array and then increment until i == x
while (i <= x) { o.push(i); i++; }
// reverse the range order if necessary
if (reverse) { o = o.reverse(); }
// return our output array
return o;
}
Then we can use Array.reduce to iterate through the range array and add each value (b) to the one before it (a) with the addition assignment operator (+=).
function sum(range) {
if (!(range instanceof Array)) {
throw new TypeError("sum() expects an Array as it's only argument");
} return range.reduce((a,b) => a+=b);
}
Testing it:
let a = range(1,10);
let b = range(5,2);
let c = range(5,2,true);
let d = range(3,-1);
let e = range(10,10);
console.log(a); // [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
console.log(b); // [ 2, 3, 4, 5 ]
console.log(c); // [ 5, 4, 3, 2 ]
console.log(d); // [ -1, 0, 1, 2, 3 ]
console.log(e); // [ 10 ]
console.log(range('test', 10)); // TypeError
console.log(range(1, 'test')); // TypeError
console.log(sum(a)); // 55
console.log(sum(b)); // 14
console.log(sum(c)); // 14
console.log(sum(d)); // 5
console.log(sum(e)); // 10
console.log(sum('test')); // TypeError
here my answer, I'd glad if you give me feedback about this solution.
let arr = [];
function range(x, y) {
for (let i = x; i <= y; i++) {
arr.push(i);
}
return arr;
}
function sum(array) {
const many = array.reduce((total, number) => {
return total + number;
}, 0);
return many;
}
console.log(sum(range(1, 10)));
From a given array of positive integers, I want to know if the sum of E elements from the array is equal to a given number N.
For example, given the array arr = [1, 2, 3, 4] , e = 3 and n = 9. It means if the sum of 3 elements in arr equals to 9. The result is true since 2 + 3 + 4 is equal to 9.
Another example with arr = [1, 2, 3, 4] , e = 2 and n = 7. It is true since 3 + 4 is equal to 7.
I'm trying to resolve it with recursion, but I'm stuck. My idea is to nest loops dynamically to walk through the elements to the array and compare them.
My attempt is this:
function subsetsum(arr, elements, n) {
loop(arr, elements, n, [], 0);
}
function loop(arr, elements, n, aux, index) {
if(aux.length != elements) {
aux[index] = arr.length - 1;
loop(arr, elements, n, aux, index + 1);
} else {
if ((elements - index + 1) < 0) {
return 0;
} else {
if (aux[elements - index + 1] > 0) {
aux[elements - index + 1]--;
loop(arr, elements, n, aux, index);
}
}
}
}
subsetsum([1, 2, 3, 4], 3, 9));
A related question is at Find the highest subset of an integer array whose sums add up to a given target. That can be modified to restrict the number of elements in the subset as follows:
// Find subset of a, of length e, that sums to n
function subset_sum(a, e, n) {
if (n < 0) return null; // Nothing adds up to a negative number
if (e === 0) return n === 0 ? [] : null; // Empty list is the solution for a target of 0
a = a.slice();
while (a.length) { // Try remaining values
var v = a.shift(); // Take next value
var s = subset_sum(a, e - 1, n - v); // Find solution recursively
if (s) return s.concat(v); // If solution, return
}
}
I've been playing around with this for a while and decided to use a short-cut, mainly the permutation code from this previous SO question.
My code uses basically uses the permutation code to create an array of all the possible permutations from the input array, then for each array (using map) grabs a slice corresponding to the number specified as amount, sums that slice and if it is the same as total returns true.
some then returns the final result as to whether there are any permutations that equals the total.
function checker(arr, amount, total) {
var add = function (a, b) { return a + b; }
return permutator(arr).map(function(arr) {
var ns = arr.slice(0, amount);
var sum = ns.reduce(add);
return sum === total;
}).some(Boolean);
}
checker([1, 2, 3, 4], 3, 9); // true
I've included two demos - 1) a demo showing this code, and 2) code that provides a more detailed breakdown: basically map returns an object containing the slice info, the sum totals and whether the condition has been met.
This is probably not what you're looking for because it's a bit long-winded, but it was certainly useful for me to investigate :)
Edit - alternatively here's a hacked version of that permutation code from the previous question that delivers the results and an array of matches:
function permutator(inputArr, amount, total) {
var results = [], out = [];
function permute(arr, memo) {
var cur, memo = memo || [];
var add = function (a, b) { return a + b; }
for (var i = 0; i < arr.length; i++) {
cur = arr.splice(i, 1);
if (arr.length === 0) {
results.push(memo.concat(cur));
}
var a = arr.slice();
// this is the change
var sum = memo.concat(cur).reduce(add);
if (memo.concat(cur).length === amount && sum === total) {
out.push(memo.concat(cur))
}
permute(a, memo.concat(cur));
arr.splice(i, 0, cur[0]);
}
return [results, out];
}
return permute(inputArr);
}
permutator([1,2,3,4], 3, 9);
DEMO
If I understand you correctly, the solution of this task must be simple like this:
function subsetsum(arr, countElements, sum) {
var length = arr.length-1;
var temp = 0;
var lastElement = length-countElements;
console.log(lastElement);
for (var i = length; i > lastElement; i--) {
temp = temp+arr[i];
console.log('Sum: '+temp);
}
if (temp === sum) {
console.log('True!');
} else {console.log('False!')}
};
subsetsum([1, 2, 3, 4], 2, 7);
I have an array full of numbers. Here's an example:
myArray = [0,1,2,4,5];
I need to find the lowest unused number starting from 1, so in this case it will be 3.
I've been reading up of using indexOf but I'm unsure how to use it for my specific purpose.
Assuming the array isn't sorted, you always start at 0, and taking into account your desire to find a highest number if there isn't one missing:
var k = [6, 0, 1, 2, 4, 5];
k.sort(function(a, b) { return a-b; }); // To sort by numeric
var lowest = -1;
for (i = 0; i < k.length; ++i) {
if (k[i] != i) {
lowest = i;
break;
}
}
if (lowest == -1) {
lowest = k[k.length - 1] + 1;
}
console.log("Lowest = " + lowest);
Logs answer 3. If 3 was also in there, would log 7 since no other number is missing.
If you aren't always starting at zero, use an offset:
var k = [6, 2, 3, 4, 5];
k.sort(function(a, b) { return a-b; }); // To sort by numeric
var offset = k[0];
var lowest = -1;
for (i = 0; i < k.length; ++i) {
if (k[i] != offset) {
lowest = offset;
break;
}
++offset;
}
if (lowest == -1) {
lowest = k[k.length - 1] + 1;
}
console.log("Lowest = " + lowest);
Logs answer 7 since none are missing after 2 which starts the sequence.
This takes a sequence starting from a number (like 1 in your example) and returns the lowest unused number in the sequence.
function lowestUnusedNumber(sequence, startingFrom) {
const arr = sequence.slice(0);
arr.sort((a, b) => a - b);
return arr.reduce((lowest, num, i) => {
const seqIndex = i + startingFrom;
return num !== seqIndex && seqIndex < lowest ? seqIndex : lowest
}, arr.length + startingFrom);
}
Example:
> lowestUnusedNumber([], 1)
1
> lowestUnusedNumber([1,2,4], 1)
3
> lowestUnusedNumber([3], 1)
1
In exchange for readability, it's slightly less optimized than the other example because it loops over all items in the array instead of breaking as soon as it finds the missing item.