二分查找
二分查找是一种基于分治策略的高效搜索算法
利用数据的有序性,每轮缩小一半搜索范围,直到找到目标或者搜索区间为空为止
例:给定一个长度为 的数组 nums ,元素按从小到大的顺序排列且不重复。请查找并返回元素 target 在该数组中的索引。若数组不包含该元素,则返回-1。
我们先初始化指针i=0和j=n-1,分别指向数组的首元素和尾元素,代表搜索区间为[0,n-1]
接下来,循环执行以下两步
-
计算中点索引m=[(i+j)/2],若为小数则向下取整
-
判断nums[m]和target的大小关系
- 当
nums[m] < target时,说明target在区间[m+1,j]中,因此执行i=m+1。 - 当
nums[m] > target时,说明target在区间[0,m-1]中,因此执行j=m-1。 - 当
nums[m] = target时,说明找到target,因此返回索引m。
- 当
-
如果数组不包含目标元素,搜索区间最终会缩小为空。返回-1
注意:由于i和j都是 int 类型,因此 可能会超出 int 类型的取值范围。为了避免大数越界,我们通常采用公式m=[i+(j-i)/2]来计算中点。
/*二分查找(双闭区间)*/
func binarySearch(nums []int,target int) int{
//初始化双闭区间[0, n-1]
i := 0
j := len(nums)-1
//循环,当搜索空间为空时跳出 当i>j时为空
for i <= j{
m := i + (j-i)/2 //中间索引
if nums[m] < target{ //此时target在中间索引的右边
i = m + 1
}else if nums[m] > target{ //此时target在中间索引的左边
j = m-1
}else { //找到目标元素
return m
}
}
//循环结束意味着区间搜索完毕,没有找到元素,返回-1
return -1
}
除了双闭区间,常见的还有左闭右开区间,即[0,n),左边界包含自身,右边界不包含自身。在这种情况下,区间[i,j)在i=j时为空
/*二分查找(左闭右开区间)*/
func binarySearch(nums []int,target int) int{
//初始化双闭区间[0, n-1]
i := 0
j := len(nums)
//循环,当搜索空间为空时跳出 当i=j时为空
for i < j{
m := i + (j-i)/2 //中间索引
if nums[m] < target{ //此时target在中间索引的右边
i = m + 1
}else if nums[m] > target{ //此时target在中间索引的左边
j = m
}else { //找到目标元素
return m
}
}
//循环结束意味着区间搜索完毕,没有找到元素,返回-1
return -1
}