golang实现二分查找

123 阅读2分钟

实现简单的二分

//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、推荐训练的算法题: