循环不变量:区间的定义就是不变量,在while循环中每一次边界的处理都要坚持根据区间的定义来操作。
循环条件的两种写法(根据心情选一种即可):
- 左闭右闭
[left, right]
→ 边界处理:right = mid - 1
- 左闭右开
[left, right)
→ 边界处理:right = mid
循环体的两种写法(根据题目问法选择对应写法):
-
问某个值在不在区间里
每个mid做等于、大于、小于三次判断,等于时返回
func search(nums []int, target int) int { lo, hi := 0, len(nums) - 1 for lo <= hi { mid := lo + (hi - lo) / 2 if nums[mid] == target { return mid } if nums[mid] < target { lo = mid + 1 } else { hi = mid - 1 } } return -1 }
func isPerfectSquare(num int) bool { lo, hi := 0, num for lo <= hi { mid := lo + (hi - lo) / 2 if mid * mid == num { return true } if mid * mid < num { lo = mid + 1 } else { hi = mid - 1 } } return false }
-
找到第一个大于等于x(最后一个小于等于x)的下标
每个mid做大于等于、小于(大于、小于等于)两次判断,循环结束返回
left
(left - 1
)func searchInsert(nums []int, target int) int { lo, hi := 0, len(nums) - 1 for lo <= hi { mid := lo + (hi - lo) / 2 if nums[mid] >= target { hi = mid - 1 } else { lo = mid + 1 } } return lo }
func binarySearch(nums []int, target int) int { lo, hi := 0, len(nums) - 1 for lo <= hi { mid := lo + (hi - lo) / 2 if nums[mid] >= target { hi = mid - 1 } else { lo = mid + 1 } } return lo } func searchRange(nums []int, target int) []int { if len(nums) <= 0 { return []int{-1, -1} } s := binarySearch(nums, target) if s >= len(nums) || nums[s] != target { return []int{-1, -1} } e := binarySearch(nums, target + 1) - 1 return []int{s, e} }
func mySqrt(x int) int { lo, hi := 0, x + 1 for lo < hi { mid := lo + (hi - lo) / 2 if mid <= x / mid { // 避免乘法溢出,用除法 lo = mid + 1 } else { hi = mid } } return lo - 1 }
参考视频:手把手带你撕出正确的二分法 | 二分查找法 | 二分搜索法 | LeetCode:704. 二分查找_哔哩哔哩_bilibili