function sumPairs(ints, s) {
let result = [];
for(let i = 0; i < ints.length; i++){
for(let j = 0; j < ints.slice(i); j++){
(ints[i] + ints[j] === s && result.length === 0) ? result.push(ints[i], ints[j]) : 0;
}
} return result;
}
sumPairs([1, 2, 3, 4, 5, 6], 10) //returns [6, 4] instead of [4,6]?
How do I fix this so that the function returns the first pair that add up to s, the second argument? I added the result.length === 0 condition in the if statement a further update would be prevented?
Just iterate over the array using for..of loop and use Set to achieve the desired result.
function sumPairs(ints, s) {
const dict = new Set();
for (let num of ints) {
if (dict.has(s - num)) return [s - num, num];
else dict.add(num);
}
}
console.log(sumPairs([1, 2, 3, 4, 5, 6], 10));
Iterations:
Iteration 1 :=> num = 1 and dict is empty
dict doesn't have 9 (because of s - num i.e 10 - 1) so add num i.e 1 to dict.
Iteration 2 :=> num = 2 and dict has 1
dict doesn't have 8 (because of s - num i.e 10 - 2) so add num i.e 2 to dict
Iteration 3 :=> num = 3 and dict has 1, 2
dict doesn't have 7 (because of s - num i.e 10 - 3) so add num i.e 3 to dict
Iteration 4 :=> num = 4 and dict has 1, 2, 3
dict doesn't have 6 (because of s - num i.e 10 - 4) so add num i.e 4 to dict
Iteration 5 :=> num = 5 and dict has 1, 2, 3, 4
dict doesn't have 5 (because of s - num i.e 10 - 5) so add num i.e 5 to dict
Iteration 6 :=> num = 6 and dict has 1, 2, 3, 4, 5
dict have 4 (because of s - num i.e 10 - 6) so return [s - num, num] i.e [4, 6]
I think you might be overcomplicating things a little. There's no need to slice() or to push(), and there's no need to keep on looping after a result has been found:
function sumPairs(ints, s) {
for (let i = 0; i < ints.length; i++) {
for (let j = i; j < ints.length; j++) {
if (ints[i] + ints[j] == s) {
return [ints[i], ints[j]];
}
}
}
}
console.log(sumPairs([1, 2, 3, 4, 5, 6], 10));
As #robby-cornelissen said there's no need to slice. And there's no need for push too as you can return the result simply.
When you do ints.slice(i) you get an array from that position.
You are comparing an int within an array in the second loop.
It didn't enter the second loop until "i === 5" which is in the ints array a [6]. Notice it didn't enter the second until you get an array of one element. Keep in mind 6 == [6] and 1<[6] and 2<[6] etc
Then it goes incrementing the value of j until you get the position of j that gets the value of ints which, summed by the value of the position i results on s.
const twoSum = (arr, target) => {
arr.sort((a, b) => a - b);
//double pointer -> increment, decrement accordingly
let leftPointer = 0;
let rightPointer = arr.length - 1;
while (leftPointer < rightPointer) {
if (arr[leftPointer] + arr[rightPointer] === target) {
return [arr[leftPointer], arr[rightPointer]];
}
if (arr[leftPointer] + arr[rightPointer] > target) {
rightPointer--;
}
if (arr[leftPointer] + arr[rightPointer] < target) {
leftPointer++;
}
}
};
console.log(twoSum([1, 2, 3, 4, 5, 6], 10));
Related
I am trying to get 5 closest elements to given element, including that element, in array. For example, if we have:
const arr = [1, 2, 3, 4, 7, 11, 12, 13, 15, 17]
and I want to get 5 closest elements to 11, it should return [4, 7, 11, 12, 13]. If i pass 1 it should return [1, 2, 3, 4, 7]. If I pass 15 it should return [11, 12, 13, 15, 17].
I'm not sure what you meant;
You might've meant a code to find the element and return the five nearest elements to it by place in the array;
Or you might've meant a code to find the 5 numbers closest to a number you say.
IF you meant the first case
There are two ways to do so,
A value as a parameter
Use this code:
function closestNByValue(arr, value, n) {
let ind = arr.indexOf(value);
let finalArr = [];
if (n > arr.length) {
finalArr = Array.from(arr);
} else if (ind == -1) {
finalArr = [];
} else if (ind <= n/2 - 0.5) {
finalArr = arr.slice(0, n);
} else if (ind >= (arr.length - n/2) - 0.5) {
finalArr = arr.slice(-n);
} else if (n%2 == 0) {
finalArr = arr.slice(ind-(n/2), ind+(n/2));
} else {
finalArr = arr.slice(ind-(n/2 - 0.5), ind+(n/2 + 0.5));
}
return finalArr;
}
console.log(closestNByValue([1, 2, 3, 4, 7, 11, 12, 13, 15, 17], 11, 5))
How does it do the job?
Okay first we need to find the index of the value and save it in ind (short form of 'index') and we check multiple different situations for what the ind is so we'd be able to output the best answer as finalArr.
There are two exceptions; what if there was no such value in our array? then ind = -1 and we'd return an empty array; or what if the number of elements nearby that we seek is larger than or equal to the arr.length? then we'd return all of the arr.
But if there were no exceptions, there are three different situations for the ind; first, ind is a number that makes us have all of the finalArr values from the first of arr, second, ind be a number that makes us have all of the finalArr values from the last of arr, and third, ind being a number that we have to select half from the indexes smaller than ind and half, larger.
If it is the third way, the way we select we'd be different depending on the oddity of the numbers we want to select.
And we'll have a conditional statement for each situation and return the finalArr.
An index as a parameter
function closestNByIndex(arr, ind, n) {
let finalArr = [];
if (n > arr.length) {
finalArr = Array.from(arr);
} else if (ind == -1) {
finalArr = [];
} else if (ind <= n/2 - 0.5) {
finalArr = arr.slice(0, n);
} else if (ind >= (arr.length - n/2) - 0.5) {
finalArr = arr.slice(-n);
} else if (n%2 == 0) {
finalArr = arr.slice(ind-(n/2), ind+(n/2));
} else {
finalArr = arr.slice(ind-(n/2 - 0.5), ind+(n/2 + 0.5));
}
return finalArr;
}
console.log(closestNByIndex([1, 2, 3, 4, 7, 11, 12, 13, 15, 17], 5, 5))
Similar to the first code it works, though we have the index and we don't search for it.
The point is, if you use the function with value, it'd do the nearest 5 elements of the first value that equals the entry but such confusion is not being tolerated in the second code.
IF you meant the second case
This is a code I coded:
const arr = [1, 2, 3, 4, 7, 11, 12, 13, 15, 17];
function allDiff(arr, num1, num2) {
const finalArr = [];
const x = Math.abs(num2 - num1);
for (let y = 0; y < arr.length; y++) {
if (Math.abs(arr[y] - num1) == x) {
finalArr.push(arr[y]);
}
}
return finalArr;
}
function deleteArr(arr, delet) {
for (let x = 0; x < arr.length; x++) {
if (delet.includes(arr[x])) {
delete arr[x];
}
}
return arr;
}
function closest(arr, num) {
const map = new Map()
arr2 = Array.from(arr);
let key, value;
for (let x = 0; x < arr2.length; x++) {
key = Math.abs(arr2[x] - num);
value = allDiff(arr2, num, arr2[x]);
arr2 = deleteArr(arr2, value);
map.set(key, value);
}
return map;
}
function closestN(arr, num, n) {
const map = closest(arr, num);
const mapKeys = Array.from(map.keys());
const mapKeysSorted = mapKeys.sort(function(a, b) {
return a - b
});
let finalArr = [];
let y;
for (let i = 0; i < mapKeysSorted.length; i++) {
if (n <= 0) {
break;
}
y = map.get(mapKeysSorted[i]);
if (n < y.length) {
finalArr = finalArr.concat(y.slice(0, n + 1));
break;
}
finalArr = finalArr.concat(y);
n -= y.length;
}
return finalArr;
}
console.log(closestN(arr, 11, 5));
It might be a little too long, but I have programmed it as you can give it any array (arr) with integer values, an integer (num) that you'd like it to be the base and another integer (n) for the number of the size of the output array, 5 in this case.
Explaining the code
The function closest would return a map of (the difference between the numbers, a list of the numbers in the arr that differs the number equal to their key).
The main function, closestN, calls the closest function and saves the map in the map variable.
Then it sorts the keys of the map in mapKeysSorted.
Now, a for loop loops through the mapKeySorted array and pushes new elements to the finalArr until the size of the finalArr reaches the number of elements we seek.
The main function is the closestN.
Here's a way to get to your goal:
To start, first thing to do is finding the index of the wanted number in the array. Example index of 1 in your array arr is 0. The index will help in extracting the numbers later on. The method findIndex will help us in finding the index.
Then, we need to find the position at which will start extaracting the closest numbers (in terms of position not value). As seen from the desired output you have provided, usually you want the returned array to be in the following structure:
output: [
2 nearest numbers (from N left),
the wanted number,
2 nearest numbers (from N right)
]
This can get tricky so we should make sure to deal with some edge case like when the wanted element is sitting at position 0.
Extract the numbers and return them as an array as described by your desired output. The use of slice method will come in handy here which allow us to extract the numbers just as we need.
Here's a live demo demonstrating solution:
const arr = [1, 2, 3, 4, 7, 11, 12, 13, 15, 17],
/** a function that returns an array containing the "5" (depending on "arr" length that could be less) nearest numbers (in terms of position) in "arr" array to the supplied number "n" */
findClosestNumbers = n => {
/** make sure we don't exceed the array length */
const toTake = 5 > arr.length ? arr.length : 5,
/** find the index of the wanted nulber "n", if "-1" is returned then "n" cannot be found ion the array "arr" */
idx = arr.findIndex(el => n == el),
/**
* from where we should start returning the nearest numbers (the position of the first number to extract from "arr"
* the below condition help deal with some edge cases like when "n" is the last element in "arr"
*/
startIdx = idx + toTake / 2 > arr.length ?
arr.length - 5 :
(idx - 2 >= 0 ?
idx - 2 :
0);
/** return the nearest numbers or return an empty array "[]" if the number "n" is not found on the array "arr" */
return idx == -1 ? [] : arr.slice(startIdx, startIdx + 5);
};
/** run for various scenarios */
console.log('For 1 =>', findClosestNumbers(1));
console.log('For 11 =>', findClosestNumbers(11));
console.log('For 15 =>', findClosestNumbers(15));
console.log('For 17 =>', findClosestNumbers(17));
.as-console-wrapper {
max-height: 100%!important;
}
The demo above is meant to help you understand how things could work and it is not the only way to get to your goal. Also, because I kept it as simple as possible, the above demo is wide open for improvements.
I am trying to solve this.
Nominal Case:
For the array[1,2,3,5,2,4,7,54], and the number 6. The sequences[1,2,3] and [4,2] will be removed because the add up to 6. function will return [5,7,54]. If two sequences overlap, remove the first sequence.
Overlapping Case:
For the array [1,2,3,9,4,1,4,6,7] and the number 5, the sequence [2,3,] and [4,1] are removed because they add up to 5. For the [4,1] case. you see that [4,1,4] represents two overlapping sequences. because [4,1] adds up to 5 first is removed and the 4 is not removed even through [1,4] adds up to 5. We say that [4,1] and [1,4] overlap to give [4,1,4] and in those cases the first of the overlapping sequences is removed . functin will return [1,9,4,6,7]
function consecutive(arr, len, num) {
var newarr = [];
for (let i = 1; i < len; i++) {
var sum = arr[i] + arr[i + 1];
if (sum == num) {
newarr.push(arr[i]);
newarr.push(arr[i + 1]);
}
}
return newarr;
}
let arr = [1, 2, 3, 5, 2, 4, 7, 54];
let len = arr.length;
let num = 6;
console.log(consecutive(arr, len, num));
Get Wrong Output
[2,4]
You could store the target index of wrong items and if no one to filter out check the next elements if they sum up to the wanted value.
function consecutive(array, num) {
return array.filter(
(wrong => (v, i, a) => {
if (i <= wrong) return false;
let sum = 0, j = i;
while (j < a.length) {
if ((sum += a[j]) === num) {
wrong = j;
return false;
}
j++;
}
return true;
})
(-1)
);
}
console.log(consecutive([1, 2, 3, 5, 2, 4, 7, 54], 6));
Is there a function how can I easily get the sum of alternating result:
Here is my simple raw list:
let x = [1, 2 , 3 , 4 , 5 , 6 ,7];
expected result:
sum by first: 1 + 3 + 5 + 7 = 16
sum by second: 2 + 4 + 6 = 12
sum by third: 3 + 6 = 9
just want to get the sum by alternating index, any suggetsions/comments TIA
You could do this:
let x = [1, 2 , 3 , 4 , 5 , 6 ,7];
function sumBy(firstelem){
var i = firstelem -1,
sum =0;
for(let k=i; k<x.length; k=k+2){
sum = sum + x[k];
}
return sum;
}
console.log(sumBy(1));
console.log(sumBy(2));
console.log(sumBy(3));
You can create your own custom function for these as follows:
const myList = [1, 2, 3, 4, 5, 6, 7];
let skipTake = (take, list) => {
let filtered = list.filter((a, i) => {
if (take == 1) {
return i % 2 == 0;
} else if (take == 2) {
return i != 0 && i % take == 1;
} else {
return i != 0 && (i + 1) % take == 0;
}
});
return filtered.reduce((agg, cur) => agg += cur);
}
console.log("first", skipTake(1, myList))
console.log("second", skipTake(2, myList))
console.log("third", skipTake(3, myList))
console.log("fourth", skipTake(4, myList))
A simple for loop will do the trick
The index inside the loop starts from 1 and goes till length-1 because of your specific requirements.
let x = [1, 2, 3, 4, 5, 6, 7];
const index = 3; //for example
let sum = 0;
for (let i = 1; i < x.length + 1; i++)
sum += (i % index == 0) ? x[i - 1] : 0;
console.log(sum);
Filter and reduce.
Change the if statement to change which indexes are selected. This one will select all even numbered indexes.
let x = [1, 2 , 3 , 4 , 5 , 6 ,7];
let y = x.filter((element, index) => {
if (index % 2 == 0) {
return element;
}
}).reduce((a, b) => a + b);
Given a list of numbers with only 3 unique numbers(1, 2, 3), sort the list in O(n) time. Plus sort the array using constant space O(1).
Example:
Input: [3, 3, 2, 1, 3, 2, 1]
Output: [1, 1, 2, 2, 3, 3, 3]
Here the solution i made (is no O(1) space and have empty spaces spaces in the array..):
What does this function is simple .. increases the size of the arrangement to double in the case that all its elements are 2; Then it goes to its previous length (current/2) to sort its elements .. if it is 1 it does nothing, if it finds a 2 it puts it in the previous maximum length + 1, it increases the variable len and eliminates the element and if it is 3 push and delete the element .. then you have empty spaces in the array and you don't meet the plus of the problem but it's O(n).
function sort(list) {
let len = list.length;
list.length=len*2
for(let i=0; i<list.length/2; i++){
let n=list[i]
if(n==2){
list[len]=n
delete list[i]
len++
}else if(n==3){
list.push(n)
delete list[i]
}
}
return list
}
console.log(sort([1,2,3,2,1,1]))
You could use the algorithm of the Dutch national flag problem:
The Dutch national flag problem 1 is a computer science programming problem proposed by Edsger Dijkstra (In a chapter of his book A Discipline of Programming Prentice-Hall, 1976). The flag of the Netherlands consists of three colors: red, white and blue. Given balls of these three colors arranged randomly in a line (the actual number of balls does not matter), the task is to arrange them such that all balls of the same color are together and their collective color groups are in the correct order.
var array = [3, 3, 2, 1, 3, 2, 1],
MID = 2,
i = 0,
j = 0,
n = array.length - 1;
while (j <= n) {
if (array[j] < MID) {
[array[i], array[j]] = [array[j], array[i]];
i++;
j++;
} else if (array[j] > MID) {
[array[n], array[j]] = [array[j], array[n]];
n--;
} else {
j++;
}
}
console.log(array);
You can count the number of occurrences of 1, 2, 3 and use that info to recreate/get the sorted array:
const arr = [3, 3, 2, 1, 3, 2, 1]
const count = arr.reduce((acc, curr) => {
acc[curr]++;
return acc;
}, {1: 0, 2: 0, 3: 0})
arr.forEach((_, j) => {
if (j < count[1])
arr[j] = 1
else if (j < count[1] + count[2])
arr[j] = 2
else
arr[j] = 3
})
console.log(arr)
Because of the fact that you know that the array can contain only 3 items, you can iterate over the entire array for each one of them, (this means that the algorithm runs 3*n times = O(3n) = O(n)).
The space restriction indicates that you need to work in-place, means, work on the input array.
This is my solution :]
function swap(i, j, arr) {
const currentVal = arr[j];
arr[j] = arr[i];
arr[i] = currentVal;
}
function sort(arr) {
let globalIndex = 0;
[1, 2, 3].forEach(item => {
for (let i = globalIndex; i < a.length; i++) {
if (arr[i] === item) {
swap(i, globalIndex, arr);
globalIndex++;
}
}
});
}
const a = [1, 2, 3, 2, 1, 1];
sort(a);
console.log(a);
According to me, you can simply initialize three variables as 0 for the counts of each 1, 2 and 3. Traverse the array once and increment the corresponding counter by 1 for values at every index i.e. if the value at a particular index is 2, increment the second variable by 1.
Once, you got the counts, (Count1 - 1)th index will be the last occurrence of 1, (Count1 + Count2 - 1)th index will be the last occurrence of 2 and (Count1 + Count2 + Count3 - 1)th index will be the last occurrence of 3.
You can traverse the whole array and assign the values accordingly.
This way is somewhat like Counting Sort but is of course not stable. However, you have another option as already mentioned in previous answers -Dutch National Flag Problem
I followed a simple bruteforce approach which still gives O(n) at the end. After all O(2N) + O(3) = O(N)
import sys
def sortNums(nums):
res = {}
mi = sys.maxsize
ma = -1 * sys.maxsize
mid = 0
for i in nums: #O(n)
if i in res:
res[i] += 1
else:
res[i] = 1
if mi > i:
mi = i
if ma < i:
ma = i
for ele in res.keys(): #O(3)
if ele != mi and ele != ma:
mid = ele
return ([mi] * res[mi]) + ( [mid] * res[mid] ) + ([ma] * res[ma]) # O(n)
print(sortNums([3, 3, 2, 1, 3, 2, 1]))
# [1, 1, 2, 2, 3, 3, 3]
I want to loop through an array and then add each value to each other (except itself + itself) and if the sum of the two values that were looped through equals the second argument in my function, and the pair of values hasn't been encountered before, then remember their indices and, at the end, return the full sum of all remembered indices.
In other words, the problem statement is: given an array A of integers and a second value s that is a desired sum, find all pairs of values from array A at indexes i, j such that i < j and A[i] + A[j] = s, and return the sum of all indexes of these pairs, with the following restriction:
don't reuse value pairs, i.e. if two index pairs i, j and k, l satisfying the above conditions are found and if A[i] == A[k] and A[j] == A[l] or A[i] == A[l] and A[j] == A[k], then ignore the pair with the higher index sum.
Example
For example, functionName([1, 4, 2, 3, 0, 5], 7) should return 11 because values 4, 2, 3 and 5 can be paired with each other to equal 7 and the 11 comes from adding the indices of them to get to 11 where:
4 + 3 = 7
5 + 2 = 7
4 [index: 1]
2 [index: 2]
3 [index: 3]
5 [index: 5]
1 + 2 + 3 + 5 = 11
Example #2
functionName([1, 3, 2, 4], 4) would only equal 1, because only the first two elements can be paired to equal 4, and the first element has an index of 0 and the second 1
1 + 3 = 4
1 [index: 0]
3 [index: 1]
0 + 1 = 1
This is what I have so far:
function functionName(arr, arg) {
var newArr = [];
for(var i = 0; i < arr.length; i++){
for(var j = i + 1; j < arr.length; j++) {
if((arr[i] + arr[j]) === arg ) {
newArr.push(i , j);
}
}
}
if(newArr.length === 0) {
return console.log(0);
}
return console.log(newArr.reduce(function(a,b){return a + b}));
}
functionName([1, 4, 2, 3, 0, 5], 7);
The problem I have is that it all works but I have the issue that once it finds a pair that equals the second argument, then it's not supposed to use the same value pairs again but mine does, e.g.:
if the array is [1,1,1] and the second argument is 2, the loop will go through and find the answer but it continues to search after it finds the sum and I only want it to use the pair [1, 1] once, so if it finds a pair like this at indexes [0, 1] then it should not include any other pair that contains the value 1.
I was thinking that i could remove the rest of the values that are the same if more than 2 are found using filter leaving me with only 2 of the same value if there is in an array thus not having to worry about the loop finding a 1 + 1 twice but is this the best way to go about doing it?
I'm still new to this but looking forward to your comments
PS I'm planning on doing this using pure JavaScript and no libraries
Link to a JS fiddle that might make things easier to see what I have.
https://jsfiddle.net/ToreanJoel/xmumv3qt/
This is more complicated than it initially looks. In fact, making a loop inside a loop causes the algorithm to have quadratic time complexity with regard to the size of the array. In other words, for large arrays of numbers, it will take a very long time to complete.
Another way to handle this problem is to notice that you actually have to use each unique value in the array only once (or twice, if s is even and you have two s/2 values somewhere in the array). Otherwise, you would have non-unique pairs. This works because if you need pairs of numbers x and y such that x + y = s, if you know x, then y is determined -- it must be equal s - x.
So you can actually solve the problem in linear time complexity (to be fair, it's sometimes n*log(n) if all values in A are unique, because we have to sort them once).
The steps of the algorithm are as follows:
Make a map whose keys are values in array A, and values are sorted lists of indexes these values appear at in A.
Move through all unique values in A (you collected them when you solved step 1) in ascending order. For each such value:
Assume it's the lower value of the searched pair of values.
Calculate the higher value (it's equal to s - lower)
Check if the higher value also existed in A (you're doing it in constant time thanks to the map created in step 1).
If it does, add the lowest indexes of both the lower and the higher value to the result.
Return the result.
Here's the full code:
function findSumOfUniquePairs(numbers, sum) {
// First, make a map from values to lists of indexes with this value:
var indexesByValue = {},
values = [];
numbers.forEach(function (value, index) {
var indexes = indexesByValue[value];
if (!indexes) {
indexes = indexesByValue[value] = [];
values.push(value);
}
indexes.push(index);
});
values.sort();
var result = 0;
for (var i = 0, maxI = values.length; i < maxI; ++i) {
var lowerValue = values[i],
higherValue = sum - lowerValue;
if (lowerValue > higherValue) {
// We don't have to check symmetrical situations, so let's quit early:
break;
}
var lowerValueIndexes = indexesByValue[lowerValue];
if (lowerValue === higherValue) {
if (lowerValueIndexes.length >= 2) {
result += lowerValueIndexes[0] + lowerValueIndexes[1];
}
} else {
var higherValueIndexes = indexesByValue[higherValue];
if (higherValueIndexes) {
result += lowerValueIndexes[0] + higherValueIndexes[0];
}
}
}
return result;
}
document.write(findSumOfUniquePairs([1, 4, 2, 3, 0, 5], 7) + '<br>'); // 11;
document.write(findSumOfUniquePairs([1, 3, 2, 4], 4) + '<br>'); // 1
document.write(findSumOfUniquePairs([1, 1, 1], 2) + '<br>'); // 1
document.write(findSumOfUniquePairs([1, 1, 1, 1], 2) + '<br>'); // 1
document.write(findSumOfUniquePairs([1, 2, 3, 1, 2, 3, 1], 4) + '<br>'); // 7
document.write(findSumOfUniquePairs([5, 5, 1, 1, 1], 6) + '<br>'); // 2
document.write(findSumOfUniquePairs([0, 5, 0, 5, 1, 1, 1], 6) + '<br>'); // 5
This works, but it mucks up the initial array.
function functionName(arr, arg) {
var newArr = [];
for(var i = 0; i < arr.length; i++){
for(var j = i + 1; j < arr.length; j++) {
if((arr[i] + arr[j]) === arg ) {
newArr.push(i , j);
arr[i] = null;
arr[j] = null;
}
}
}
if(newArr.length === 0) {
return console.log(0);
}
return console.log(newArr.reduce(function(a,b){return a + b}));
}
Solution with loops with restart, if a sum is found. the found summands are stored in usedNumbers and later sorted and used to get the index for summing the index.
The sorting and the last index provides the correct start position for the Array.prototype.indexOf.
Edit:
what about [1,1,1,1], 2 ... should that be 6 or 1? – Jaromanda X 21
#JaromandaX that should be 1, after the pair is found with the values then it shouldn't look for a pair with the same values again – Torean
This version takes care of the requirement.
function f(array, sum) {
var arrayCopy = array.slice(0),
usedNumbers = [],
index = 0,
indexA = 0,
indexB,
a, b;
while (indexA < arrayCopy.length) {
indexB = indexA + 1;
while (indexB < arrayCopy.length) {
a = arrayCopy[indexA];
b = arrayCopy[indexB];
if (a + b === sum) {
usedNumbers.push(a, b);
arrayCopy = arrayCopy.filter(function (i) { return a !== i && b !== i; });
indexA--; // correction to keep the index
break;
}
indexB++;
}
indexA++;
}
return usedNumbers.sort().reduce(function (r, a, i) {
index = array.indexOf(a, i === 0 || a !== usedNumbers[i - 1] ? 0 : index + 1);
return r + index;
}, 0);
}
document.write(f([1, 4, 2, 3, 0, 5], 7) + '<br>'); // 11
document.write(f([1, 1, 1], 2) + '<br>'); // 1
document.write(f([5, 5, 1, 1, 1], 6) + '<br>'); // 2
document.write(f([0, 5, 0, 5, 1, 1, 1], 6) + '<br>'); // 5
document.write(f([1, 1, 1, 1], 2) + '<br>'); // 1
The solution below is very compact. It avoids unnecessary checks and loops only through the relevant elements. You can check the working codepen here:
http://codepen.io/PiotrBerebecki/pen/RRGaBZ.
function pairwise(arr, arg) {
var sum = 0;
for (var i=0; i<arr.length-1; i++) {
for (var j=i+1; j<arr.length; j++) {
if (arr[i] <= arg && arr[j] <= arg && arr[i] + arr[j] == arg) {
sum += i+j;
arr[i] = arr[j] = NaN;
}
}
}
return sum;
}
console.log( pairwise([1, 1, 0, 2], 2) ) // should return 6
Under the hood:
Start looping from the element with index (i) = 0.
Add a second loop only for the elements which are later in the array. Their index j is always higher than i as we are adding 1 to i.
If both elements (numbers) are less than or equal to to the arg, check if their sum equals to the arg. This avoids checking the sum if either of the numbers are greater than the arg.
If the pair has been found then change their values to NaN to avoid further checks and duplication.
This solution should have a time complexity of 0(n) or linear
Much faster than two nested for-loops. This function will give you the two indices that add up to the target number. It can easily be modified to solve any other configuration of this problem.
var twoSum = function(nums, target) {
const hash = {}
for(let i = 0; i < nums.length; i++) {
hash[nums[i]] = i
}
for(let j = 0; j < nums.length; j++) {
let numToFind = target - nums[j]
if(numToFind in hash && hash[numToFind] !== j) {
return [hash[numToFind], j]
}
}
return false
};
console.log(twoSum([1,2,3,5,7], 5))
In Python:
def twoSum(self, nums: List[int], target: int) -> List[int]:
myMap = {}
for i in range(len(nums)):
myMap[nums[i]] = i
for j in range(len(nums)):
numToFind = target - nums[j]
if numToFind in myMap and myMap[numToFind] != j:
return [myMap[numToFind], j]
print(twoSum([1,2,3,5,7], 5))
In Java:
import java.util.*;
class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> map = new HashMap<>();
for(Integer i = 0; i < nums.length; i++) {
map.put(nums[i], i);
}
for(Integer j = 0; j < nums.length; j++) {
Integer numToFind = target - nums[j];
Integer myInt = map.get(numToFind);
if(map.containsKey(numToFind) && myInt != j) {
return new int[] {myInt , j};
}
}
return new int[] {0, 0};
}
}
System.out.println(twoSum([1,2,3,5,7], 5))