Related
Given an array [[1, 7, 3, 8],[3, 2, 9, 4],[4, 3, 2, 1]],
how can I find the sum of its repeating elements? (In this case, the sum would be 10.)
Repeated values are - 1 two times, 3 three times, 2 two times, and 4 two times
So, 1 + 3 + 2 + 4 = 10
Need to solve this problem in the minimum time
There are multiple ways to solve this but time complexity is a major issue.
I try this with the recursion function
How can I optimize more
`
var uniqueArray = []
var sumArray = []
var sum = 0
function sumOfUniqueValue (num){
for(let i in num){
if(Array.isArray(num[i])){
sumOfUniqueValue(num[i])
}
else{
// if the first time any value will be there then push in a unique array
if(!uniqueArray.includes(num[i])){
uniqueArray.push(num[i])
}
// if the value repeats then check else condition
else{
// we will check that it is already added in sum or not
// so for record we will push the added value in sumArray so that it will added in sum only single time in case of the value repeat more then 2 times
if(!sumArray.includes(num[i])){
sumArray.push(num[i])
sum+=Number(num[i])
}
}
}
}
}
sumOfUniqueValue([[1, 7, 3, 8],[1, 2, 9, 4],[4, 3, 2, 7]])
console.log("Sum =",sum)
`
That's a real problem, I am just curious to solve this problem so that I can implement it in my project.
If you guys please mention the time it will take to complete in ms or ns then that would be really helpful, also how the solution will perform on big data set.
Thanks
I would probably use a hash table instead of an array search with .includes(x) instead...
And it's also possible to use a classical for loop instead of recursive to reduce call stack.
function sumOfUniqueValue2 (matrix) {
const matrixes = [matrix]
let sum = 0
let hashTable = {}
for (let i = 0; i < matrixes.length; i++) {
let matrix = matrixes[i]
for (let j = 0; j < matrix.length; j++) {
let x = matrix[j]
if (Array.isArray(x)) {
matrixes.push(x)
} else {
if (hashTable[x]) continue;
if (hashTable[x] === undefined) {
hashTable[x] = false;
continue;
}
hashTable[x] = true;
sum += x;
}
}
}
return sum
}
const sum = sumOfUniqueValue2([[1, 7, 3, 8],[[[[[3, 2, 9, 4]]]]],[[4, 3, 2, 1]]]) // 10
console.log("Sum =", sum)
This is probably the fastest way...
But if i could choose a more cleaner solution that is easier to understand then i would have used flat + sort first, chances are that the built in javascript engine can optimize this routes instead of running in the javascript main thread.
function sumOfUniqueValue (matrix) {
const numbers = matrix.flat(Infinity).sort()
const len = numbers.length
let sum = 0
for (let i = 1; i < len; i++) {
if (numbers[i] === numbers[i - 1]) {
sum += numbers[i]
for (i++; i < len && numbers[i] === numbers[i - 1]; i++);
}
}
return sum
}
const sum = sumOfUniqueValue2([[1, 7, 3, 8],[[[[[3, 2, 9, 4]]]]],[[4, 3, 2, 1]]]) // 10
console.log("Sum =", sum)
You could use an objkect for keeping trak of seen values, like
seen[value] = undefined // value is not seen before
seen[value] = false // value is not counted/seen once
seen[value] = true // value is counted/seen more than once
For getting a value, you could take two nested loops and visit every value.
Finally return sum.
const
sumOfUniqueValue = (values, seen = {}) => {
let sum = 0;
for (const value of values) {
if (Array.isArray(value)) {
sum += sumOfUniqueValue(value, seen);
continue;
}
if (seen[value]) continue;
if (seen[value] === undefined) {
seen[value] = false;
continue;
}
seen[value] = true;
sum += value;
}
return sum;
},
sum = sumOfUniqueValue([[1, 7, 3, 8], [3, 2, 9, 4], [4, 3, 2, 1]]);
console.log(sum);
Alternatively take a filter and sum the values. (it could be more performat with omitting same calls.)
const
data = [[1, 7, 3, 8], [3, 2, 9, 4, 2], [4, 3, 2, 1]],
sum = data
.flat(Infinity)
.filter((v, i, a) => a.indexOf(v) !== a.lastIndexOf(v) && i === a.indexOf(v))
.reduce((a, b) => a + b, 0);
console.log(sum);
You can flatten the array, filter-out single-instance values, and sum the result:
const data = [
[ 1, 7, 3, 8 ],
[ 3, 2, 9, 4 ],
[ 4, 3, 2, 1 ]
];
const numbers = new Set( data.flat(Infinity).filter(
(value, index, arr) => arr.lastIndexOf(value) != index)
);
const sum = [ ...numbers ].reduce((a, b) => a + b, 0);
Another approach could be the check the first and last index of the number in a flattened array, deciding whether or not it ought to be added to the overall sum:
let sum = 0;
const numbers = data.flat(Infinity);
for ( let i = 0; i < numbers.length; i++ ) {
const first = numbers.indexOf( numbers[ i ] );
const last = numbers.lastIndexOf( numbers[ i ] );
if ( i == first && i != last ) {
sum = sum + numbers[ i ];
}
}
// Sum of numbers in set
console.log( sum );
Consider:
let N = 12
let arr = [1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1]
Your task is to find the maximum number of times an odd number is continuously repeated in the array.
What is the approach for this?
This is the hint:
1 is repeated 4 times from index 0 to index 3 → 4 times
2 is repeated 5 times from index 4 to index 8 → 5 times
1 is repeated 3 times from index 9 to index 11 → 3 times
The odd numbers in array are 1s.
1 occurs 4 times and 3 times continuously, so 4 is the maximum number of times an odd number is continuously repeated in this array.
function longestRepeatedOdd(N, array) {
// Write code here
let count = 0;
for (let i = 0; i <= array.length-1; i++){
if (array[i] % 2 !== 0){
count++
}else if (array[i] % 2 === 0){
break;
}
}
console.log(count)
}
You can use Array.reduce() to keep track of the current run of odd numbers and the maximum.
We use an accumulator value with a max and current field, the current field the current run of odd numbers and the max field is the longest run.
If the current run exceeds the max we set the max to this value.
function longestRepeatedOdd(arr) {
return arr.reduce((acc, n, idx) => {
acc.current = (n === arr[idx - 1] ? acc.current: 0) + (n % 2);
acc.max = (acc.current > acc.max) ? acc.current: acc.max;
return acc;
}, { max: 0, current: 0 }).max;
}
const inputs = [
[1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1],
[7, 7, 4, 4, 1, 1, 1, 1, 1, 1, 4, 3],
[1, 2, 2, 2]
]
inputs.forEach((input, idx) => {
console.log(`Test input #${idx + 1} result:`, longestRepeatedOdd(input))
})
Your answer is definitely valid. Just replace break with continue.
function longestRepeatedOdd(N, array) {
//write code here
let count = 0;
for (let i = 0; i <= array.length-1; i++){
if (array[i] % 2 !== 0){
count++
}else if (array[i] % 2 === 0){
continue;
}
}
return count
}
Try reduce and creating a JavaScript object that reports its value:
const count = arr.reduce((accumulator, value) => {
return {...accumulator, [value]: (accumulator[value] || 0) + 1};
}, {});
Object { 1: 7, 2: 5 }
console.log(count);
Number one repeated 7 times and number two 5 times.
I have a group of numbers:
const numbers = [ 4, 6, 2, 1, 5, 3, 6, 11 ]
And I would like to return these numbers in groups where the sum is closest to x. For example if x was 13, the expected output would be:
// console.log(result)
[ 2, 11 ] // sum is 13
[ 3, 4, 5 ] // sum is 12
[ 1, 6, 6 ] // sum is 13
All numbers must be used. "Closest" being below the number (not above 13), so the above example would be acceptable but if the sum was 14 it would not be. This should find the best results (closest to 13) and remove each number from the pool of options in the array when it has been grouped.
How would I approach this?
How about something like this?
const x = 13;
const result = [];
let numbers = [4, 6, 2, 1, 5, 3, 6, 11];
let i = numbers.length;
while (--i > -1) {
const length = result.length;
let target = x - numbers[i];
let a = numbers.length - 1;
while (target > 0) {
if (numbers[--a] !== target) {
if (a === -1) {
a = numbers.length - 1;
target--;
}
continue;
}
result[length] ??= [];
result[length].push(numbers[a]);
target = x - numbers[i];
for (const entry of result[length]) {
target -= entry;
}
numbers = [...numbers.slice(0, a), ...numbers.slice(a + 1)];
a = numbers.length - 1;
}
if (!result[length]) {
continue;
}
result[length].push(numbers[numbers.length - 1]);
numbers = numbers.slice(0, -1);
i = numbers.length;
}
console.log(result);
It's kinda crude though.
I am attempting to add the results of doubling every other number in an array to a new array. However the code only seems to be pushing the first index that is doubled. I assume the problem is with the .push line but I am not sure. Thanks for any help!
Here is the code I have:
const addTwoDigits = n => {
return n % 10 + Math.floor(n / 10);
}
const validateCred = array => {
let sumNums = []
let i = array.length - 2
while (i > 0) {
let doubleNum = (array[i] * 2)
if (doubleNum > 9) {
let addedNum = addTwoDigits(doubleNum)
sumNums.push(addedNum)
} else {
sumNums.push(doubleNum)
}
i--;
return sumNums;
}
}
const testArray = [4, 2, 1, 6, 5, 7, 5]
console.log(validateCred(testArray));
I was hoping the sumNums array would contain every other digit doubled (starting with '' in the test array and moving left) but it only returns [ 5 ].
You returned the value in the loop. When the compiler comes in loop then first time it returns the value and break the loop.
const addTwoDigits = n => {
return n % 10 + Math.floor(n / 10);
}
const validateCred = array => {
let sumNums = []
let i = array.length - 2
while (i > 0) {
let doubleNum = (array[i] * 2)
if (doubleNum > 9) {
let addedNum = addTwoDigits(doubleNum)
sumNums.push(addedNum)
} else {
sumNums.push(doubleNum)
}
i--;
}
return sumNums;
}
const testArray = [4, 2, 1, 6, 5, 7, 5]
console.log(validateCred(testArray));
Your can try this code.
I worked on a problem where you are given an array of numbers and a target sum, and it's your job to find a pair of numbers that sum up to the target number. Here was my solution using simple nested for loops:
function findPairForSum(integers, target) {
var output = [];
for (var i = 0; i < integers.length; i++) {
for (var j = 0; j < integers.length; j++) {
if (i !== j && integers[i] + integers[j] === target) {
output.push(integers[i], integers[j]);
return output;
}
}
}
return 'not possible';
}
findPairForSum([3, 34, 4, 12, 5, 2], 9); // --> [4, 5]
My question is, is there a cleaner way to write this solution using higher order functions (perhaps forEach?)
Here was my attempt to use forEach:
function findPairForSum(integers, target) {
var output = [];
integers.forEach(function(firstNum) {
integers.forEach(function(secondNum) {
if (firstNum + secondNum === target) {
output.push(firstNum, secondNum);
}
})
})
if (output === []) {
return 'not possible';
}
return output;
}
findPairForSum([3, 34, 4, 12, 5, 2], 9); // --> [ 4, 5, 5, 4 ]
I tried putting a return after the two pushes, but it did not return anything. So instead, I put the return at the very end.
Why won't it return after the initial two pushes? I want it to stop right there, and only push the two numbers. Instead, by putting the return at the end, it pushed 4 numbers. It should be [4,5] but I got something like [4,5,5,4].
Any advice and help would be much appreciated!
Assume we have the following set of numbers, and we must find a subset of 2 numbers whose sum is 9:
Numbers: 4, 5, 6
Your current code iterates both with i and j from 0 to length. This means that the following iterations match the condition:
Indices: 0, 1, 2
Numbers: 4, 5, 6 // (i) (j)
---------------- // ↓ ↓
i j // Numbers[0] + Numbers[1] === 9
j i // Numbers[1] + Numbers[0] === 9
As you can see, the numbers 4 and 5 are matched twice, in 2 iterations:
i === 0 && j === 1
i === 1 && j === 0
You can avoid this by making sure one simple condition is met:
j must at all times be greater than i
This condition can be met met by initializing j with i + 1 in the inner for loop:
for (var i = 0; i < integers.length; i++) {
for (var j = i + 1; j < integers.length; j++) {
// ...
}
}
This way, j can never be 0 when i is 1, because the inner for-loop will run to completion before i is ever incremented once more. Once that happens, a brand new inner for-loop is created, in which j is again set to i + 1. The following diagram is the result:
Indices: 0, 1, 2
Numbers: 4, 5, 6
----------------
i j
X i // ← j can never be 0 if (i === 1),
// so the same set is never evaluated twice.
In other words, only the following combinations for i and j are checked at most:
Indices: 0, 1, 2
----------------
i j
i j
i j
is there a cleaner way to write this solution using higher order functions (perhaps forEach?)
A for loop is actually a fine solution for your use-case. They allow you to break early - after the first time you find a valid pair of numbers. forEach or other array iterator functions on the other hand will always continue until all set indices are visited.
You are actually breaking early in your first example with the statement return output;
When you use forEach on a set of numbers with multiple valid sets, you'll always get back all numbers involved:
Indices: 0, 1, 2, 3
Numbers: 4, 5, 6, 3 // (i) (j)
------------------- // ↓ ↓
i j // Numbers[0] + Numbers[1] === 4 + 5 === 9
i j // Numbers[2] + Numbers[3] === 6 + 3 === 9
forEach, map, reduce and the like do not allow you to break early. The following snippet demonstrates this issue of the diagram above:
function findPairForSum(integers, target) {
var output = [];
integers.forEach(function(firstNum, i) {
// slice(i + 1) has the same effect as for (var j = i + 1; ...)
integers.slice(i + 1).forEach(function(secondNum, j) {
if (firstNum + secondNum === target) {
// There is no way here to stop the iteration of either
// forEach call... T_T
output.push(firstNum, secondNum);
}
});
})
if (output.length) {
return output;
}
return 'not possible';
}
console.log(findPairForSum([4, 5, 6, 3], 9)); // --> [4, 5, 6, 3]
This is why I highly recommend sticking with the for loops for this specific use case. With for loop you can simply return as you already did as soon as you encounter a valid set of numbers:
function findPairForSum(integers, target) {
for (var i = 0; i < integers.length; i++) {
for (var j = i + 1; j < integers.length; j++) {
if (integers[i] + integers[j] === target) {
return [integers[i], integers[j]];
}
}
}
return 'not possible';
}
console.log(findPairForSum([4, 5, 6, 3], 9)); // --> [4, 5]
This could be your solution:
function findPairForSum(arr, sum) {
var pairs = [];
arr.forEach(n1 => {
var n2 = arr.find(n2 => n1 + n2 == sum)
if (n2) pairs.push([n1, n2]);
});
return pairs;
}
var sums = findPairForSum([3, 34, 4, 12, 6, 2], 9);
console.log(sums)
The problem is, you iterate from the start of the array for the inner loop. You could use a copy which starts at the index of the outer loop plus one and exit early on a found value.
But this does not solves the problem with multiple pairs. The result is simply wrong.
function findPairForSum(integers, target) {
var output = [];
integers.forEach(function(firstNum, i) {
integers.slice(i + 1).some(function(secondNum) {
if (firstNum + secondNum === target) {
output.push(firstNum, secondNum);
return true;
}
});
});
return output.length && output || 'not possible';
}
// console.log(findPairForSum([3, 34, 4, 12, 5, 2], 9));
console.log(findPairForSum([3, 34, 4, 4, 12, 5, 2, 4, 5], 9));
For a solution, you need to remember which pairs are used. This approach works with only one loop and a hash table for counting missing values.
If a pair is found, the counter is decremented and the two values are pushed to the result set.
function findPairForSum(integers, target) {
var hash = Object.create(null),
output = [];
integers.forEach(function(value) {
if (hash[value]) {
output.push(target - value, value);
hash[value]--;
return;
}
hash[target - value] = (hash[target - value] || 0) + 1;
});
return output.length && output || 'not possible';
}
console.log(findPairForSum([3, 34, 4, 4, 12, 5, 2, 4, 5], 9));
This is expected, since you didn't compare the indexes.
This inner array should only loop through the indexes which larger than the outer index.
You can achieve this by using the 2nd parameter, index, in forEach's callback function:
const ints = [3, 34, 4, 12, 5, 6, 2];
function findPairForSum(integers, target) {
let result;
integers.forEach((val1, idx1) => {
integers.forEach((val2, idx2) => {
if (idx1 < idx2 && val1 + val2 === target) {
result = [val1, val2];
}
})
})
return result;
}
console.log(findPairForSum(ints, 9));
Use can reduce your array into another which has sum equals target value:
const ints = [3, 34, 4, 12, 6, 2];
const value = 9;
const resp = ints.reduce((acc, ele, idx, self) => {
let found = self.find(x => x + ele == value)
return found ? [found, ele] : acc;
}, []);
console.log(resp); // [3, 6]
You can use Array.prototype.some which will stop execution as soon as the condition becomes true. See below code.
function findPairForSum(arr, sum) {
var pairs = [];
arr.some(n1 => {
var n2 = arr.find(n2 => n1 + n2 == sum)
if (n2) {
pairs.push(n1, n2); return true;
};
return false;
});
return pairs.length > 0 ? pairs : "not possible";
}
console.log(findPairForSum([3, 34, 4, 12, 7, 2], 9));