I am trying to get all subarray which have sum 0 in javascript ? I am able to do that in O(n^2) like this
function getSubArray(input){
let result =[]
sum= 0
let a = [];
for(var i =0;i<input.length;i++){
a=[];
sum =0 ;
for (let j = i; j < input.length; j++) {
a.push(input[j])
sum+=input[j];
if(sum ===0){
result.push(a);
}
}
}
return result
}
when I call above function console.log(getSubArray([1, 2, -3, 0, 4, -5, 2, -1])) it is printed in all subarray but in O(n^2).
I tried to optimism this in O(n) using map
function getSubArray1(input) {
let sum = 0,
map = {0:[-1]};
for (let i = 0; i < input.length; i++) {
sum += input[i];
if (!map[sum]) {
map[sum] = [i];
}else {
map[sum].push(i)
let val = map[sum];
for (let j = 0; j < val.length; j++) {
console.log(val[j])
}
}
}
}
above function not working not giving all subarray? is there any way to do this?
I take the reference from here
https://www.techiedelight.com/find-sub-array-with-0-sum/
That site has an article titled "Find subarrays with given sum in an array". It has C++, Java, and Python implementations.
I just ported the Java (and a bit of Python) code to JavaScript.
const main = () => {
const input = [4, 2, -3, -1, 0, 4], target = 0;
console.log(subarraySum(input, target));
console.log(subarraySumMap(input, target));
};
const subarraySum = (nums, k) => {
const results = [];
for (let start = 0; start < nums.length; start++) {
let sum = 0;
for (let end = start; end <= nums.length; end++) {
sum += nums[end];
if (sum === k) {
results.push(nums.slice(start, end + 1));
}
}
}
return results;
}
const subarraySumMap = (nums, k) => {
const insert = (hashMap, key, value) =>
hashMap.set(key, (hashMap.get(key) || []).concat(value));
const results = [], hashMap = new Map();
let sum = 0;
insert(hashMap, 0, -1);
for (let index = 0; index < nums.length; index++) {
sum += nums[index];
if (hashMap.has(sum - k)) {
let list = hashMap.get(sum - k);
list.forEach(value => {
results.push(nums.slice(value + 1, index + 1));
});
}
insert(hashMap, sum, index);
}
return results;
}
main();
.as-console-wrapper { top: 0; max-height: 100% !important; }
<!-- References: -->
<!-- https://leetcode.com/problems/subarray-sum-equals-k/solution/ -->
<!-- https://www.techiedelight.com/find-subarrays-given-sum-array/ -->
<!-- ∀ x ⊆ ∑ { 4, 2, -3, -1, 0, 4 } = 0 -->
Related
I'm trying to create this script: https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/seek-and-destroy
After the comment "Verify and delete" is where I have the problem.
I try to check all the elements form the array 'theCheck' with the elements from 'destroyers' and if the elements dont match then the script will push that value to the output array.
But it pushes every element regardless.
Expected output value: [1,1]
Current output value value: [1,2,3,1,2,3]
function destroyer(arr) {
let theCheck = [];
let destroyers = [];
let output = [];
for (let i = 1; i < arguments.length; i++) {
destroyers.push(arguments[i]);
}
for (let i = 0; i < arguments[0].length; i++) {
theCheck.push(arguments[0][i])
}
//Verify and delete
var j = 0
for (let i = 0; i < theCheck.length; i++) {
for (j = 0; j < destroyers.length; j++) {
if (theCheck[i] !== destroyers[j]) {
output.push(theCheck[i])
break;
}
}
}
console.log(theCheck)
console.log(destroyers)
console.log(output)
return arr;
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3);
With the current code you're looping through the destroyers and anytime you find a destroyer that doesn't match the item you're checking you're adding it to the output. But because you've got two items in the destroyers array it is guaranteed that one of the two is not going to match the particular item that you're checking.
Below is a version where we work out whether any of the destroyers are found to match the item that we're checking, and only if it doesn't we're adding it to the output:
function destroyer(arr) {
let theCheck = [];
let destroyers = [];
let output = [];
for (let i = 1; i < arguments.length; i++) {
destroyers.push(arguments[i]);
}
for (let i = 0; i < arguments[0].length; i++) {
theCheck.push(arguments[0][i])
}
//Verify and delete
var j = 0
for (let i = 0; i < theCheck.length; i++) {
let found = false;
for (j = 0; j < destroyers.length; j++) {
if (theCheck[i] === destroyers[j]) {
found = true;
}
}
if(!found) output.push(theCheck[i]);
}
console.log(theCheck)
console.log(destroyers)
console.log(output)
return arr;
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3);
You could use the includes function to tidy this up a little:
function destroyer(arr) {
let theCheck = [];
let destroyers = [];
let output = [];
for (let i = 1; i < arguments.length; i++) {
destroyers.push(arguments[i]);
}
for (let i = 0; i < arguments[0].length; i++) {
theCheck.push(arguments[0][i])
}
//Verify and delete
var j = 0
for (let i = 0; i < theCheck.length; i++) {
if(!destroyers.includes(theCheck[i]))
output.push(theCheck[i]);
}
console.log(theCheck)
console.log(destroyers)
console.log(output)
return arr;
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3);
function destroyer(input, ...arr) {
return input.filter(element => !arr.includes(element));
}
console.log(destroyer([1, 2, 3, 1, 2, 3], 2, 3));
Input Arr=[1,2,3,4,5,6,7,8,9,10]
Expected output:-
Arr1 = [1,2,3,4,5,6,7] = 28
Arr2 = [8,9,10] = 27
The sum of arrays should be almost the same..
It can also be 3 or more parts
How to achieve this via custom function?
let Arr = [1,2,3,4,5,6,7,8,9,10]
const numberOfParts = 2
function SplitArr(Array, Parts){
/* ... */
}
let result = SplitArr(Arr,numberOfParts)
/* result should be [[1,2,3,4,5,6,7],[8,9,10]] */
/* output can be in any format as long as it can get the parts */
I think you can't do that directly by JS functions.
You have to create a custom function to achieve this.
I have considered dividing the array into 2 equal parts.
You can't always split the array equally. Here in this array, you can't partition array into more than 2 subparts, otherwise it will give more than 3 parts as some of the elements are present there having sum more than the partitioned Sum.
Note: I treated the array to be sorted, otherwise it depends on the usecase.
Note: I have updated the old implementation based on the updated question requirement
let arr=[1,2,3,4,5,6,7,8,9,10]
function splitArrayEqually(arr, parts=2){
//get the total sum of the array
let sum = arr.reduce((currentSum, value) => currentSum+value ,0);
//get the half sum of the array
let partitionedSum = Math.ceil(sum/parts);
let start=0, end=0, currentSum=0;
let splittedArray=[];
//get the index till which the sum is less then equal partitioned sum
while(end < arr.length){
if(currentSum+arr[end] > partitionedSum){
splittedArray.push(arr.slice(start,end));
start = end; //start new window from current index
currentSum = 0; //make sum =0
}
//add current end index to sum
currentSum += arr[end];
end++;
}
splittedArray.push(arr.slice(start));
return splittedArray;
}
splitted = splitArrayEqually(arr,3);
console.log(splitted)
let Arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
const numberOfParts = 3
function sumOfArray(arr) {
if (arr) {
if (arr.length > 0) {
let sum = 0
for (let i = 0; i < arr.length; i++) sum += arr[i]
return sum
} else {
return 0
}
} else {
return 0
}
}
function SplitArr(Array, Parts) {
let lastIndex = 0
let result = []
function getReamingSum(arr) {
let psum = sumOfArray(Array.slice(lastIndex)) / Parts
console.log('psum ' + psum)
return psum + Parts
}
let psum = getReamingSum(Array)
for (let j = 0; j < Parts; j++) {
let total = 0
for (let i = 0; i < Array.length; i++) {
if (i >= lastIndex) {
total += Array[i]
if (total < psum || j === Parts - 1) {
if (result[j]?.length > 0) {
result[j].push(Array[i])
} else {
let arr = []
arr.push(Array[i])
result[j] = arr
}
lastIndex = i + 1
}
}
}
}
return result
}
let result = SplitArr(Arr, numberOfParts)
console.log(result)
Assuming the array isn't sorted,using a 2D array, with each sub array with sum almost equal to (sum of array / n).
let arr = [9,2,10,4,5,6,7,8,1,3]
arr.sort(function(a, b) { return a - b; });
const sum = arr.reduce((a, b) => a + b, 0);
const n = 2;
const result = [];
let s = 0;
let j = 0;
result[j] = [];
for(let i=0; i<arr.length; i++){
if(s <= Math.floor(sum/n)){
result[j].push(arr[i]);
s +=arr[i];
}
else{
s = 0;
j = j + 1;
result[j] = [];
result[j].push(arr[i]);
}
}
console.log(result)
O/P:
[ [1, 2, 3, 4,5, 6, 7], [ 8, 9, 10 ] ]
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const splitArray = (arr,parts) => {
const totalSum = arr.reduce((acc, item) => {
acc += item;
return acc;
}, 0)
const splitSum = Math.floor(totalSum / parts);
const arrObj = arr.reduce((acc, item,index) => {
acc.sum = acc.sum || 0;
acc.split = acc.split || {};
const pointer = Math.floor(acc.sum / splitSum);
//console.log(item,acc.sum, splitSum, pointer);
acc.split[pointer] = acc.split[pointer] || [];
acc.split[pointer].push(item);
acc.splitSum = splitSum;
acc.sum += item;
return acc;
}, {})
return arrObj;
}
console.log(splitArray(arr,2).split)
You're better off making a custom function:
let currentTotal = 0
let tempList = []
Arr.forEach(val => {
if (val >= 27) {
// push tempList to a new array
tempList = [];
currentTotal = val;
} else {
tempList.push(val);
currentTotal += val;
}
})
I wrote the code, but for some reason it displays the index 1, 2, 3, while 3 + 4 will in no way be equal to target (6).
var twoSum = function(nums, target) {
let sum = [];
var n = 2;
for(let i = 0; i < nums.length; i++) {
for(let a = 1; a < nums.length; a++) {
if(nums[i] + nums[a] == target) {
sum.push(i);
sum.push(a);
}
}
}
let unique = sum.filter((e, i) => sum.indexOf(e) === i )
return unique/* .slice(0, n); */
};
console.log(twoSum([1,3,4,2],6))
Input
[1,3,4,2]
6
Output
[1,2]
Expected
[2,3]
As per my comment, start the inner loop at a = i + 1 to avoid summing numbers with themselves as well as to avoid checking the same combination twice, e.g (1, 2) and (2, 1):
var twoSum = function(nums, target) {
let sum = [];
let n = 2;
for (let i = 0; i < nums.length; i++) {
for (let a = i + 1; a < nums.length; a++) {
if (nums[i] + nums[a] === target) {
sum.push(i);
sum.push(a);
}
}
}
let unique = sum.filter((e, i) => sum.indexOf(e) === i )
return unique/* .slice(0, n); */
};
I'm trying to get all the numbers that are higher than the average of a given Array.
(this goes into an HTML page so it's with document.write
this is what I wrote:
sumAndBigger(arrayMaker());
function sumAndBigger(array) {
for (i = 0; i < array.length; i++) {
sum += array;
}
var equalAndBigger = []
var avg = sum / array.length;
for (i = 0; i < array.length; i++) {
if (array[i] > avg) {
equalAndBigger.push(array[i])
}
}
document.write('The numbers are: ' + equalAndBigger)
}
function arrayMaker() {
var array = [];
for (i = 0; i < 5; i++) {
var entrie = +prompt('Enter a number: ');
array.push(entrie)
}
return array;
}
This doesn't seem to work.. what am I doing wrong here?
Thanks in advance!
Ok so here I am giving you a one-liner code to get all the elements from the array that are "strictly greater than" the average value
let array = [1, 2, 3, 4, 5]
let allNums = array.filter(v => v > array.reduce((x, y) => x + y) / array.length);
Explanation
array.reduce((x, y) => x + y) → sum of all elements in the array
array.reduce((x, y) => x + y) / array.length → getting the average
Output
[4, 5]
MORE DETAILED CODE
function getAverage(arr) {
let sum = 0;
for (let i = 0; i < arr.length; i++) {
sum += arr[i];
}
return sum / arr.length;
}
function getGreaterThanAverage(arr) {
let avg = getAverage(arr);
let numbers = [];
for (let i = 0; i < arr.length; i++) {
if (arr[i] > avg) {
numbers.push(arr[i]);
}
}
return numbers;
}
Here is the idea:
var a = [4, 5, 6];
for (var m = 0; m < a[0]; m++)
for (var n = 0; n < a[1]; n++)
for (var p = 0; p < a[2]; p++)
console.log(`${m} + ${n} + ${p} = ${m+n+p}`);
Live Copy:
// This just tells the Stack Snippets in-snippet console not
// to throw away entries once it reaches a max (the default max
// is just the last 50 logs).
console.config({maxEntries: Infinity});
var a = [4, 5, 6];
for (var m = 0; m < a[0]; m++)
for (var n = 0; n < a[1]; n++)
for (var p = 0; p < a[2]; p++)
console.log(`${m} + ${n} + ${p} = ${m+n+p}`);
/* This just makes the console take up the full output area */
.as-console-wrapper {
max-height: 100% !important;
}
The code would get longer if the array a has more indexes. Could the code be shorten using Array.map or filter or a function?
We can do this without taking up massive amounts of memory, and fairly simply, by using recursion:
const process = (array, n, numbers) => {
if (n < array.length) {
// Not done yet, recurse once for each number at this level
const max = array[n];
for (let i = 0; i < max; ++i) {
process(array, n + 1, [...numbers, i]);
}
} else {
// Done with this level, process the numbers we got
console.log(`${numbers.join(" + ")} = ${numbers.reduce((s, e) => s + e)}`);
}
}
process([4, 5, 6], 0, []);
Live Copy, with cross-checking against your results to ensure the above does the same thing:
// This just tells the Stack Snippets in-snippet console not
// to throw away entries once it reaches a max (the default max
// is just the last 50 logs).
console.config({maxEntries: Infinity});
function thisSolution() {
const results = [];
const process = (array, n, numbers) => {
if (n < array.length) {
// Not done yet, recurse once for each number at this level
const max = array[n];
for (let i = 0; i < max; ++i) {
process(array, n + 1, [...numbers, i]);
}
} else {
// Done with this level, process the numbers we got
const result = numbers.reduce((s, e) => s + e);
results.push(result);
console.log(`${numbers.join(" + ")} = ${result}`);
}
}
process([4, 5, 6], 0, []);
return results;
}
function yourSolution() {
const results = [];
var a = [4, 5, 6];
for (var m = 0; m < a[0]; m++)
for (var n = 0; n < a[1]; n++)
for (var p = 0; p < a[2]; p++)
results.push(m + n + p);
return results;
}
const thisResult = thisSolution();
const yourResult = yourSolution();
if (thisResult.some((entry, index) => entry !== yourResult[index])) {
console.log("WRONG");
} else {
console.log("RIGHT");
}
/* This just makes the console take up the full output area */
.as-console-wrapper {
max-height: 100% !important;
}
This never goes deep into the stack (a.length + 1 stack frames, to be precise, so four in the example case). It builds up a number of temporary arrays (145 in the example case) that max out at a.length entries, releasing them as soon as they aren't needed anymore (a max of four are retained at any given time). Here's the quick and dirty metrics on that:
let maxStack = 0;
let stack = 0;
let totalArrays = 0;
let maxArrays = 0;
let arrays = 0;
// A wrapper for counting stack frames
const process = (...args) => {
if (++stack > maxStack) {
maxStack = stack;
}
const result = process2(...args);
--stack;
return result;
};
const process2 = (array, n, numbers) => {
if (n < array.length) {
// Not done yet, recurse once for each number at this level
const max = array[n];
for (let i = 0; i < max; ++i) {
++totalArrays;
if (++arrays > maxArrays) {
maxArrays = arrays;
}
process(array, n + 1, [...numbers, i]);
--arrays;
}
} else {
// Done with this level, process the numbers we got
//console.log(`${numbers.join(" + ")} = ${numbers.reduce((s, e) => s + e)}`);
}
}
process([4, 5, 6], 0, []);
++maxArrays; // To account for the one in the last argument above
++totalArrays; // "
console.log(`Max stack: ${maxStack}, max arrays: ${maxArrays}, total arrays: ${totalArrays}`);
It's easier if you break it down. First, you need to create a series per every element of your array.
let series = num => Array.from({ length: num + 1 }, (n, i) => i); //creates an array with nums from 0 to num.
That's the first part of your question. Then you need to do a cross product of your series.
Basically for two series [1, 2, 3] and [1, 2, 3, 4] you'll end up with a set of 12 elements:
[2, 3, 4, 5, 3, 4, 5, 6, 4, 5, 6, 7]
And for that you could do:
let crossProduct = (a1, a2) => Array.prototype.concat.call(...a1.map(n1 => a2.map(n2 => n1 + n2)));
Now all you need to do is have a crossProduct for every series.
let final = numbers.map(series).reduce(crossProduct);
And there you have it:
let numbers = [4, 5, 6];
let series = num => Array.from({ length: num + 1 }, (n, i) => i);
let crossProduct = (a1, a2) => Array.prototype.concat.call(...a1.map(n1 => a2.map(n2 => n1 + n2)));
let final = numbers.map(series).reduce(crossProduct);
console.log(final);
Edit: If it's from 0 to the number before (e.g. 4 is [0, 1, 2, 3]) then just take the + 1 in the series function.
2nd Edit: Less objects created for your crossProduct:
let crossProduct = (a1, a2) => {
let resultingSet = [];
for(let i = 0; i < a1.length; i++)
for(let j = 0; j < a2.length; j++)
resultingSet.push(a1[i] + a2[j]);
return resultingSet;
} //only one array is created
And if you want to avoid having the series on memory all the time:
let numbers = [4, 5, 6];
let series = function* (num){
for(let i = 0; i < num; i++){
yield i;
}
}
let crossProduct = (set, num) => {
let resultingSet = [];
for(let i = 0; i < set.length; i++){
for(let j of series(num)){
resultingSet.push(set[i] + j);
}
}
return resultingSet;
}
let final = numbers.reduce(crossProduct, [0]);
console.log(final);
Another solution that doesn't consume alot of memory and fairly efficient is by using an array that represnt the value of the indexes and update it each iteration.
first you create an array that represent in each element the amount of iterations you need to run in order to update the indexes respectively for example for this array [1, 2, 3 ,4 ,5] you will get:
[280, 140, 20, 5, 1] this means that index[0] will be updated each 280 iterations, index[1] will be updated each 140 iterations and so on..
totally you will run arr[n] * arr[n-1] * arr[n-2] * .... * arr[0] iterations as you did with ordinary nested for loop.
var arr = [1, 2, 7, 4, 5];
var indexes = Array.from({length: arr.length}, () => 0);
iterationsPerElement = arr.map((_, i) => arr.slice(i+1).reduce((acc, elem) => acc * elem, 1));
var totalIterations = iterationsPerElement[0] * arr[0];
for(var iteration = 1; iteration <= totalIterations; iteration++) {
// sum those indexes
console.log(`sum = ${indexes.reduce((acc, index) => acc + index, 0)}`);
// update indexes
for(i = 0; i < indexes.length; i++) {
if(iteration % iterationsPerElement[i] == 0) {
indexes[i]++;
// empty the indexes on the right
for(var j=i+1; j <indexes.length; j++) {
indexes[j] = 0;
}
}
}
}