Beginner Swift 3: How to find pairs in array that add up to given number

前端 未结 4 1815
深忆病人
深忆病人 2021-01-22 05:40

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

4条回答
  •  不知归路
    2021-01-22 06:21

    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..

    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)
        })
    }
    

提交回复
热议问题