二分查找(Binary Search)也叫折半查找。二分查找将顺序遍历搜索的时间复杂度优化到了。二分查找有两个要求,一个是数列有序,另一个是数列使用顺序存储结构(比如数组)。
听说“二分查找算法发明多年之后才第一次被写对”。让我们一起把它写正确吧。
本题关键点:
- 有序的(升序) 数组
- 你可以假设数组中的所有元素是不重复的
今天结合代码讲一讲二分查找。重点都在注释里。对于本题来说元素是否重复无所谓,找到任意一个返回其索引就是了。
// 在nums中找target。
// 如果存在返回下标。
// 如果不存在就返回-1。
func search(nums []int, target int) int {
l := len(nums)
if l == 0 {
return -1
}
var (
// 初始两端索引,限定一个左闭右闭区间
low int
high = l-1
)
for low <= high { // 这里要包含“等于”。具体原因在下面。
// 找中间位置。
// 当 low == high 时,算出来的mid和它们相等。
// target也要和这个位置的值比较的。
// 所以for循环的判断条件中要包含“等于”。
// 计算mid可以用(low+high)/2,但加法计算结果可能溢出(不是针对本题)。所以换一种写法。
// >>1 就是除以2。
mid := low + (high-low)>>1
v := nums[mid]
if v == target {
// 找到了
return mid
}
if v < target {
// target比中间位置的值大。
// 如 [...,1,2,3,4,5,...], v=3, target=5。
// 这时要向右继续找。
// high不变,low更新为mid+1。
low = mid+1
} else {
// target比中间位置的值小。
// 如 [...1,2,3,4,5,...],v=3,target=1。
// 这时要向左继续找。
// low不变,high更新为mid-1。
high = mid-1
}
}
// 没找到
return -1
}