[英]Swift: Find closest value in array with binary search
II try to find the closest value in an array using binary search. II尝试使用二进制搜索在数组中找到最接近的值。 Everything works fine as long as the value I am looking for is not smaller than the smallest value in the array.
只要我要查找的值不小于数组中的最小值,一切就可以正常工作。
Unfortunately, the debugger did not result in anything helpful. 不幸的是,调试器没有产生任何帮助。 So I ask the community now.
所以我现在问社区。 You can also try the code directly in the Xcode Playground.
您也可以直接在Xcode Playground中尝试代码。 I tried to change an other searched value to a smaller value as in the array, but got the same error.
我试图将另一个搜索到的值更改为一个较小的值,与数组中的值相同,但是出现了相同的错误。 Error: error: Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0).
错误:错误:执行被中断,原因:EXC_BAD_INSTRUCTION(代码= EXC_I386_INVOP,子代码= 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))
I expected the fourth output 100. Because 100 is the closest value to 5 in the fourth array. 我期望第四个输出为100。因为100是第四个数组中最接近5的值。
I can see you put in some boundary checks, but they should happen at the beginning of the function instead of the end. 我可以看到您进行了一些边界检查,但是它们应该在函数的开头而不是结尾处进行。 Allow me to rewrite the whole function:
请允许我重写整个函数:
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))
Some notes: 一些注意事项:
if left == right - 1 { ... }
allows the while
loop to terminate. if left == right - 1 { ... }
允许while
循环终止。 Otherwise, integer division will round middle
down to `left, resulting in a infinite loop. middle
向下舍入到“左”,从而导致无限循环。 case ..<target
is a short hand for "when arr[middle] < target
" case ..<target
是“当arr[middle] < target
”的简写 while
should always find a solution and return from inside but I have not thoroughly tested that yet. while
应该总是找到一个解决方案,然后从内部回来,但是我还没有彻底测试过。 If you find a case where it reaches the last fatalError
, let me know. fatalError
,请告诉我。 target = 6
. target = 6
均为1。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.