【问题标题】:Swift: Find closest value in array with binary searchSwift:使用二进制搜索在数组中查找最接近的值
【发布时间】:2019-11-17 11:18:57
【问题描述】:

我尝试使用二进制搜索在数组中找到最接近的值。只要我要查找的值不小于数组中的最小值,一切正常。

不幸的是,调试器没有提供任何帮助。所以我现在问社区。您也可以直接在 Xcode Playground 中尝试代码。我尝试将其他搜索值更改为数组中的较小值,但得到了相同的错误。 错误:错误:执行被中断,原因:EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)。

func closestValue(_ arr: [Int],_ target: Int) -> Int {
    var leftPointer = 0
    var rightPointer = arr.count-1

    while leftPointer < rightPointer {
        let middleIndex = (leftPointer + rightPointer) / 2
        let middleValue = arr[middleIndex]

        if middleValue == target {
            return middleValue
        }

        //Check for out of bounds error
        let leftIndex = middleIndex-1
        let leftValue = arr[leftIndex]

        if leftValue <= target && middleValue >= target {
            let leftDistance = abs(leftValue-target)
            let rightDistance = abs(middleValue-target)

            if leftDistance <= rightDistance {
                return leftValue
            } else {
                return middleValue
            }
        }
        if middleValue <= target {
            leftPointer = middleIndex+1
        } else {
            rightPointer = middleIndex
        }
    }
    guard let first = arr.first, let last = arr.last else {
        fatalError()
    }

    if target <= first {
        return first
    } else if target >= last {
        return last
    } else {
        fatalError()
    }
}
let first = [1,2,3,5,5,5,7,9,19,11] // 6 --> 5
let second = [1,2,3] // 8 --> 3
let third = [9, 10, 22, 59, 67, 72, 100] // 70 --> 72
let fourth = [100, 101, 102] //5 --> 100    => Heres the error

print(closestValue(first, 6))
print(closestValue(second, 8))
print(closestValue(third, 110))
print(closestValue(fourth, 5))

我期望第四个输出 100。因为 100 是第四个数组中最接近 5 的值。

【问题讨论】:

  • 我认为你的问题出在“let leftIndex = middleIndex-1; let leftValue = arr[leftIndex];” middleIndex 可以为零,这将导致 leftIndex 为 -1。

标签: arrays swift binary-search


【解决方案1】:

我可以看到您进行了一些边界检查,但它们应该发生在函数的开头而不是结尾。请允许我重写整个函数:

func closestValue(_ arr: [Int],_ target: Int) -> Int {
    // Array must not be empty
    guard arr.count > 0 else { fatalError("Array must not be empty") }

    // If array has only 1 element, that element is the closest
    guard arr.count > 1 else { return arr[0] }

    // To use binary search, your array must be ever-increasing or ever-decreasing
    // Here, we require that the array must be ever-increasing
    for index in 1..<arr.count {
        if arr[index - 1] > arr[index] {
            fatalError("Array must be monotonous increasing. Did you forget to sort it?")
        }
    }

    // If the target is outside of the range of the array,
    // return the edges of the array
    guard arr.first! <= target else { return arr.first! }
    guard target <= arr.last! else { return arr.last! }

    // Now some actual searching
    var left = 0
    var right = arr.count - 1

    while left < right {
        if left == right - 1 {
            return abs(arr[left] - target) <= abs(arr[right] - target) ? arr[left] : arr[right]
        }

        let middle = (left + right) / 2
        switch arr[middle] {
        case target:
            return target
        case ..<target:
            left = middle
        default:
            right = middle
        }
    }

    fatalError("It should never come here")
}


let first = [1,2,3,5,5,5,7,9,11,19] // 6 --> 5
let second = [1,2,3] // 8 --> 3
let third = [9, 10, 22, 59, 67, 72, 100] // 70 --> 72
let fourth = [100, 101, 102] //5 --> 100

print(closestValue(first, 6))
print(closestValue(second, 8))
print(closestValue(third, 70))
print(closestValue(fourth, 5))

一些注意事项:

  • if left == right - 1 { ... } 允许 while 循环终止。否则,整数除法会将middle 向下舍入到`left,从而导致无限循环。
  • case ..&lt;target 是“当arr[middle] &lt; target”的简写
  • while 应该总能找到解决方案并从内部返回,但我还没有彻底测试过。如果您发现到达最后一个fatalError 的案例,请告诉我。
  • 第一个示例有两个答案:5 和 7 都与 target = 6 相差 1。

【讨论】:

  • 感谢您的精彩解释,我下班后会尝试您的解决方案。
猜你喜欢
  • 1970-01-01
  • 2021-10-19
  • 2021-01-28
  • 1970-01-01
  • 2021-12-30
  • 2021-12-28
  • 1970-01-01
  • 2013-12-06
  • 2011-02-21
相关资源
最近更新 更多