Need to loop through an array and say whether there are any pairs of numbers that sum to 8
e.g. [1,2,4,4] = yes
Can get it working with lots of nested if stateme
Please try the below code. It will give you all the unique pairs whose sum will be equal to the targetSum. It performs the binary search so will be better in performance. The time complexity of this solution is O(NLogN)
((arr,targetSum) => {
if ((arr && arr.length === 0) || targetSum === undefined) {
return false;
} else {
for (let x = 0; x <=arr.length -1; x++) {
let partnerInPair = targetSum - arr[x];
let start = x+1;
let end = (arr.length) - 2;
while(start <= end) {
let mid = parseInt(((start + end)/2));
if (arr[mid] === partnerInPair) {
console.log(`Pairs are ${arr[x]} and ${arr[mid]} `);
break;
} else if(partnerInPair < arr[mid]) {
end = mid - 1;
} else if(partnerInPair > arr[mid]) {
start = mid + 1;
}
}
};
};
})([0,1,2,3,4,5,6,7,8,9], 10)
You want to check all sums numbers[i] + numbers[j]
where
i < j
, and the easiest way to do so is a nested loop like this:
func checkPairs(in numbers: [Int], forSum target: Int) -> Bool {
for i in 0..<numbers.count {
for j in i+1..<numbers.count {
if numbers[i] + numbers[j] == target {
return true
}
}
}
return false
}
The array lookups can be avoided by using the enumerated()
method
and array slices:
func checkPairs(in numbers: [Int], forSum target: Int) -> Bool {
for (i, x) in numbers.enumerated() {
for y in numbers[i+1 ..< numbers.count] {
if x + y == target {
return true
}
}
}
return false
}
Here x
is the current element of the outer loop and i
its
index. y
is the current element of the inner loop which starts
enumerating at i + 1
.
Example:
print(checkPairs(in: [1, 2, 4, 4], forSum: 8))
print(checkPairs(in: [1, 2, 4, 4], forSum: 7))
The above function could be written more compactly as
func checkPairs(in numbers: [Int], forSum target: Int) -> Bool {
return numbers.enumerated().contains(where: { (i, x) -> Bool in
numbers[i+1 ..< numbers.count].contains(target - x)
})
}
If the given numbers are in non-decreasing order then you can improve the performance by terminating the inner loop if the target sum cannot be reached:
func checkPairs(in numbers: [Int], forSum target: Int) -> Bool {
for (i, x) in numbers.enumerated() {
for y in numbers[i+1 ..< numbers.count] {
if x + y == target {
return true
}
if x + y > target {
break
}
}
}
return false
}
For an array of non-decreasing numbers an even more efficient
solution would be to do a binary search for target - x
for each array element x
. Here is a possible binary search
implementation (a variant of https://stackoverflow.com/a/40226976/1187415):
extension Collection where Iterator.Element: Comparable {
func binarySearch(element: Iterator.Element) -> Bool {
var low = startIndex
var high = endIndex
while low != high {
let mid = index(low, offsetBy: distance(from: low, to: high)/2)
if self[mid] < element {
low = index(after: mid)
} else if element < self[mid] {
high = mid
} else {
return true
}
}
return false
}
}
which can then be used as
func checkPairs(in numbers: [Int], forSum target: Int) -> Bool {
return numbers.enumerated().contains(where: { (i, x) -> Bool in
numbers[i+1 ..< numbers.count].binarySearch(element: target - x)
})
}
Using two pointer technique.
Time Complexity: O(n)
Other solutions mentioned here have Time Complexity: O(n2)
func isPairSum()-> Bool{
let array = [3, 5, 9, 2, 8, 10, 11]
let sum = 22
var i = 0
var j = array.count - 1
while i<j {
let valueSum = array[i] + array[j]
if valueSum == sum {
return true
}
else if valueSum > sum {
j -= 1
}
else if valueSum < sum {
i += 1
}
}
return false
}
And If you want the values of the pair, instead of returning Bool, you can return Tuple of type Int.
You can use nested for loops with indexes:
for (firstIndex, firstElement) in numbersSet.enumerated() {
for (secondIndex, secondElement) in numbersSet.enumerated() {
if firstIndex != secondIndex && firstElement + secondElement == 8 {
return true
}
}
}