二分查找
二分查找也称折半查找(Binary Search),它是一种效率较高的查找方法。但是,折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列。
二分查找从思路上来说并不复杂,但是在细节上有很多需要注意的地方。
1.二分查找框架
int binarySearch(int[] nums, int target) {
int left = 0, right = ...;
while(...) {
//这里使用left+(left+right)/2而不使用(left+right)/2是为了避免left+right结果太大导致溢出
int mid = left+(right-left) / 2;
if (nums[mid] == target) {
...
} else if (nums[mid] < target) {
left = ...
} else if (nums[mid] > target) {
right = ...
}
}
return ...;
}
2.寻找一个数(基本二分搜索)
在一个有数排列中寻找一个数
int binarySearch(int[] nums, int target) {
int left = 0, right = nums.length-1;
while(right>=left) {
//这里使用left+(left+right)/2而不使用(left+right)/2是为了避免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;
}
如果排列是一个数组为[1,2,2,2,3,3,4],怎样找到数组最左侧或者最右侧的2呢?
这里我们要引出左侧边界二分搜索和右侧边界二分搜索
3.左侧边界二分搜索
主要是要理解在左侧边界搜索时,target<=nums[mid]时,right=mid-1;这一步
int left_bound(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] >= target) {
right = mid - 1;
}
}
// 最后要检查 left 越界的情况
if (left >= nums.length || nums[left] != target)
return -1;
return left;
}
4.右侧边界二分搜索
同理,理解target>=nums[mid]时,left=mid+1;
int right_bound(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] <= target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid - 1;
}
}
// 最后要检查 right 越界的情况
if (right < 0 || nums[right] != target)
return -1;
return right;
}