应用场景:

寻找一个数、寻找左侧边界、寻找右侧边界

解题思路:

  • 二分查找算法是典型的「减治思想」的应用,我们使用二分查找将待搜索的区间逐渐缩小,以达到「缩减问题规模」的目的;
  • 掌握二分查找的两种思路:
    • 思路 1:在循环体内部查找元素:while (left <= right);
    • 思路 2:在循环体内部排除元素:while (left < right)。
  • 全部使用左闭右闭区间,不建议使用左闭右开区间,反而使得问题变得复杂;
  • 不建议背模板,每一步都要清楚为什么这样写,不要跳步,更不能想当然。

计算 mid 时需要技巧防止溢出,建议写成: mid = left + (right - left) / 2
不要出现 else,而是把所有情况用 else if 写清楚,这样可以清楚地展现所有细节

在循环体内部查找元素(解决简单问题时有用)

例:搜索一个数字,如果存在,返回其索引,否则返回 -1。

  1. class Solution:
  2. def search(self, nums, target):
  3. nums.sort() # 排序;倒序 nums.sort(reverse = True)
  4. l = len(nums)
  5. if l == 0:
  6. return -1
  7. left = 0
  8. right = l - 1
  9. while left <= right:
  10. mid = int(left + (right - left)/2)
  11. if nums[mid] == target:
  12. return mid
  13. elif nums[mid] > target: # 下一轮搜索[left,mid-1]
  14. right = mid - 1
  15. else:
  16. left = mid + 1 # 下一轮搜索[mid+1,right]
  17. return -1
  18. s = Solution()
  19. t = s.search([3, 5, 2, 1], 3)
  20. print(t)

python 中扩展/ // %

在pyhon3中/是真除法。
3/2=1.5
取整数位//
3//2=1
%表示求余数
5%2=1

例如:寻找左、右侧边界的二分搜索对比

  1. # 搜索一个数
  2. int binarySearch(int[] nums, int target) {
  3. int left = 0;
  4. int right = nums.length - 1; // 注意
  5. while(left <= right) { // 注意
  6. int mid = (right + left) / 2;
  7. if(nums[mid] == target)
  8. return mid;
  9. else if (nums[mid] < target)
  10. left = mid + 1; // 注意
  11. else if (nums[mid] > target)
  12. right = mid - 1; // 注意
  13. }
  14. return -1;
  15. }
  16. # 寻找左边界
  17. int left_bound(int[] nums, int target) {
  18. if (nums.length == 0) return -1;
  19. int left = 0;
  20. int right = nums.length; // 注意
  21. while (left < right) { // 注意
  22. int mid = (left + right) / 2;
  23. if (nums[mid] == target) {
  24. right = mid;
  25. } else if (nums[mid] < target) {
  26. left = mid + 1;
  27. } else if (nums[mid] > target) {
  28. right = mid; // 注意
  29. }
  30. }
  31. return left;
  32. }
  33. 寻找右侧边界
  34. int right_bound(int[] nums, int target) {
  35. if (nums.length == 0) return -1;
  36. int left = 0
  37. right = nums.length;
  38. while (left < right) {
  39. int mid = (left + right) / 2;
  40. if (nums[mid] == target) {
  41. left = mid + 1; // 注意
  42. } else if (nums[mid] < target) {
  43. left = mid + 1;
  44. } else if (nums[mid] > target) {
  45. right = mid;
  46. }
  47. }
  48. return left - 1; // 注意