总纲
思路很简单,细节是魔鬼。分为三个常用场景:寻找一个数,寻找左侧边界,寻找右侧边界。最后给出力扣上的题目例子。
还可以在GitHub上观看哦。AlgorithmNotes
基础框架
int binarySearch(int[] nums, int target) {
int left = 0, right = ...;
while(...) {
int mid = (right + left) / 2;
if (nums[mid] == target) {
...
} else if (nums[mid] < target) {
left = ...
} else if (nums[mid] > target) {
right = ...
}
}
return ...;
}
- 把所有情况都写清楚,展示所有细节。
- mid = left + (right - left) / 2,防止溢出。
- 三个框架可以合成一个,但适用面很小,不如单独的左区间或右区间使用广。
寻找一个数
int binarySearch(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target)
return mid;
else if (nums[mid] < target)
left = mid + 1;
else if (nums[mid] > target)
right = mid - 1;
}
return -1;
}
最基础的二分查找,每次查找都是左闭右闭区间。
- 循环条件是 <=;
- 更新是 left=mid+1,right=mid-1。
必要条件是数组内无重复整数。
寻找左侧边界
int left_bound(int[] nums, int target) {
if (nums.length == 0) return -1;
int left = 0;
int right = nums.length;
while (left < right) {
int mid = (left + right) / 2;
if (nums[mid] == target) {
right = mid;
} else if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid;
}
}
return left;//此处返回left,right都可,因为相等
}
每次查找都是左闭右开区间。
- 循环条件是 left < right;
- 更新是 left = mid + 1, right = mid,可以理解为下一次搜索区间是 [left,mid), [mid+1,right)
- 每次找到target时,因为存在重复数字且要找的是左边界,所以不断向左收缩, right = mid。
寻找右侧边界
int right_bound(int[] nums, int target) {
if (nums.length == 0) return -1;
int left = 0, right = nums.length;
while (left < right) {
int mid = (left + right) / 2;
if (nums[mid] == target) {
left = mid + 1;
} else if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid;
}
}
return left - 1;
}
- 循环条件是 left < right;
- 更新是 left = mid + 1, right = mid,可以理解为下一次搜索区间是 [left,mid), [mid+1,right);
- 每次找到target时,因为存在重复数字且要找的是右边界,所以不断向右收缩, left = mid + 1;
- 返回 left - 1,因为更新时 left = mid + 1,所以循环结束时 nums[left-1] 才是target。
题目
题号 | 题目 | 链接 |
---|---|---|
704 | 二分查找(打板题) | 105265723 |
33 | 搜索旋转排序数组 | 105265887 |
35 | 搜索插入位置(打板题) | 105265922 |
153 | 寻找旋转排序数组中的最小值 | 105265935 |
154 | 寻找旋转排序数组中的最小值II | 105265998 |
162 | 寻找峰值 | 105266055 |
275 | H指数II | 105266073 |