实现简单的二分
//pass
func binarySearchEasy(arr []int, target int) int {
l := 0
r := len(arr)
for l < r {
mid := int(uint(l+r) >> 1)
if arr[mid] > target {
r = mid
} else if arr[mid] < target {
l = mid + 1
} else {
return mid
}
}
return -1
}
这个比较简单,我们找到就可以返回下标了,不需要边界值
找等于target的左边界
//pass
func binarySearchLeftEquals(arr []int, target int) int {
//多用个ans好理解
l, r, ans := 0, len(arr), -1
for l < r {
mid := int(uint(l+r) >> 1)
if arr[mid] > target {
r = mid
} else if arr[mid] < target {
l = mid + 1
} else {
r = mid
ans = mid
}
}
return ans
}
这里,我们使用一个ans来保存我们需要的答案,这样更好理解。
代码解释
初始化l和r我们知道我们的范围是[l,r),所以这也是为什么我们循环条件为什么设置成l < r
当arr[mid] > target,这时候我们知道[mid,r)是不满足题意的,满足要求的是[l,mid)这个范围,所以让r = mid
当arr[mid]<target,这个时候满足要求的是[mid+1,r),所以l = mid+1
当arr[mid] == target,这个下标可能是我们需要的,我们用ans记录一下,然后继续缩小范围看看有没有更小的下标满足我们的要求,所以r = mid
如果并没有等于target的值,那就返回我们ans = -1这个初始值了。
其实,这个实现我们可以直接使用goang的库函数,sort.SearchInts(arr,target)实现
找等于target的右边界
//pass
func binarySearchRightEquals(arr []int, target int) int {
//多加一个ans非常好理解
l, r, ans := 0, len(arr), -1
for l < r {
mid := int(uint(l+r) >> 1)
if arr[mid] < target {
l = mid + 1
} else if arr[mid] > target {
r = mid
} else {
l = mid + 1
ans = mid
}
}
return ans
}
这个思路和找左边界差不多,唯一一点的区别就是,当出现等于target的时候,我们往右边缩,
及l = mid + 1
大于等于target的最左边
什么意思呢?
比如arr = [1,3,5,19,21,199],target = 7
大于7的有19、21、199,我们需要的是最左边的,所以19就是我们想要的答案
//大于等于target的最左端 --测试通过,(len(arr)表示没有任何数字大于等于target)
func binarySearchLeftGr(arr []int, target int) int {
//下面这个又是什么个原理呢?l这个就不多说了,主要是r。
//当arr[mid]>=target的时候,这个mid可能是答案,我们不保存一下吗?我们保存了,在r上
//r上的数有两个意义:1、[l,r)是可能范围;2、r是可能满足的答案
l, r := 0, len(arr)
for l < r {
mid := int(uint(l+r) >> 1)
if arr[mid] >= target {
r = mid
} else if arr[mid] < target {
l = mid + 1
}
}
return r
}
解释在代码里面了,这个实现我们需要的是知道答案藏在r里面。当然,退出条件我们知道l == r,但是返回r更方便我们的记忆。
其实,这个实现我们可以直接使用goang的库函数,sort.SearchInts(arr,target)实现
小于等于target的最右边
//小于等于target的最右端 --测试通过(-1表示没有任何数字小于等于target)
func binarySearchRightLe(arr []int, target int) int {
l, r := 0, len(arr)
for l < r {
mid := int(uint(l+r) >> 1)
if arr[mid] > target {
r = mid
} else if arr[mid] <= target {
//赋完值之后,l的意义:1、[l,r)可能存在;2、l-1可能是答案
l = mid + 1
}
}
return l - 1
}
这个实现也是和上面的差不多的,只是我们的答案藏在l-1这里罢了
总结
1、二分查找这个东西包含的细节很多,写的时候非常容易写错,所以我们要记住这几个模板,做题的时候可以用上。
2、推荐训练的算法题: