二分法pro max版
什么是二分法
简单来说,就是在一堆有序数组中查找特定元素的搜索算法。大致思路如下:
(1)从中间元素开始查找,若等于target,则返回,否则执行下一步;
(2)若target 大于/小于 中间元素值,分别缩进左/右边界,则在右/左半区间继续查找,执行(1)中操作;
(3)若数组为空,则表示找不到该目标元素target,返回-1。
最基本的二分查找
int binarySerach(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;
}
下面回答几个问题:
1.为什么 while 循环的条件中是 <=,而不是 <
在while循环中,使用<=是因为需要将查找范围缩小至只有一个元素时,也需要继续比较。如果只使用<,会漏掉最后一个元素的比较。因此,使用<=可以确保最后一个元素也能够被比较。
2.为什么left = mid + 1,right = mid - 1?
本算法的搜索区间是两端都闭的,即[left, right]。当我们发现索引mid不是要找的目标元素时,下一步应该去搜索哪里呢?当然是去搜索[left, mid-1]或者[mid+1, right],因为mid已经搜索过,应该从搜索区间中去除。
3.算法存在的不足
当查找元素的数组中存在重复的值,而我们想要获得最左侧或者最右侧边界的索引,这显然是无法办到的。例如 nums = [1,3,4,5,5,5,6] ,target为5时,此时返回的索引值是3,当我们想要获得最左侧或者最右侧的索引时,是显然无法处理的。
寻找最左侧边界的索引
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;
} else if (nums[mid] == target) {
// 缩紧右侧边界
right = mid - 1;
}
}
// 判断 left 越界情况
if (left >= nums.length || nums[left] != target)
return -1;
return left;
}
我们需找到 target 的最左侧索引,当 nums[mid] == target 时,不要立即返回,而要收紧右侧边界以锁定左侧边界。
寻找最右侧边界的索引
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;
} else if (nums[mid] == target) {
// 缩紧左侧边界
left = mid + 1;
}
}
// 判断 right 越界情况
if (right < 0 || nums[right] != target)
return -1;
return right;
}
我们需找到 target 的最右侧索引,当 nums[mid] == target 时,不要立即返回,而要收紧左侧边界以锁定右侧边界。