二分法小结
二分法小结
通过一些leetcode上面的题目总结一下二分算法
- 有序二分搜索[无重复元素]。
- 有序确定边界[有重复元素]
- 非有序下的搜索[无重复元素]。
- 非有序下的确定边界[有重复元素]。
有序二分搜索
从一个有序数组(最好是每个元素均不重复, 一般说明重复的话 就是要搜寻边界啦)当中判断元素是否存在,存在返回下标,不存在返回-1。
模板
//模板1:
int binarySearch(int []nums, int target)
{
int lo = 0, hi = nums.length - 1;
while(lo <= hi)
{
int mid = lo + (hi - lo) / 2;
if(nums[mid] < target)
lo = mid + 1;
else if(nums[mid] > target)
hi = mid - 1;
else
return mid;
}
return -1;
}
//模板2:
int binarySearch(int []nums, int target)
{
int lo = 0, hi = nums.length;
while(lo < hi)
{
int mid = lo + (hi - lo) / 2;
if(nums[mid] < target)
lo = mid + 1;
else if(nums[mid] > target)
hi = mid;
else
return mid;
}
return -1;
}
两个模板之间的区别
第一个模板确保每次查找的区间为一个闭区间
, 而第二个模板确保每次查找的区间为一个左闭右开的区间
。两个模板均可使用。
题目
有序确定边界
搜索有序数组当中的元素时候,当搜寻到的时候不能立马停止(因为元素重复的情况存在
),而是应该根据搜寻的是左还是右边界来决定向左边还是右边继续搜索,在余下搜索过程当中如果还能搜寻到当前元素,则更新下标值。
模板
这里只用 左闭右开区间
的模板改一下即可:
//寻找左边界为例子.
int binarySearch(int []nums, int target)
{
int ans = -1;
int lo = 0, hi = nums.length;
while(lo < hi)
{
int mid = lo + (hi - lo) / 2;
if(nums[mid] < target)
lo = mid + 1;
else if(nums[mid] > target)
hi = mid;
else
{
ans = mid;
hi = mid; //如果是右边界, 则为 lo = mid + 1;
}
}
return ans;
}
题目
非有序下的搜索
这种情况下数组不再有序,我们需要自己分析得出下一个搜索区间是左边还是右边,条件依然是使用 nums[mid]
来进行判断,但与之比较的因素待定,需要仔细分析一下。
模板
使用左闭又开
模板来进行修改, 伪代码如下:
int binarySearch(int nums[], int target)
{
int lo = 0, hi = nums.length;
while(lo < hi)
{
int mid = lo + (hi - lo) / 2;
/*
根据 nums[mid] 和 target 等因素判断target 在mid的左边还是
右边, 此时不能仅仅的比较大小了,根据所见问题可以有以下思路参考:
1. 非有序数组对半分后,一半有序一半无序,则在有序二分搜索,无序
部分继续对半,这需要使用递归的思想了。 [leetcode 33]
2. 判断 mid 和 target 是否处于同一个有序范围内, 在则根据nums
[mid] 和 target 大小比较确定下一个区间, 不在则想办法向
target所在的区间缩小。 [leetcode 33]
3. 如果没有给定target值, 比如说 leetcode 153 这种情况, 则需要
判断nums[i]则需要和相邻元素比较才能确定, 而没有具体targe值
来判断是否相等了。 [leetcode 153]
*/
}
return -1;
}
题目
非有序下的确定边界
非有序条件下, 各个元素可重复,那么在上一种情况下找到元素的基础上,必须要找到边界上此元素才行。
(使用左闭又开模板
)在此情况下,当出现元素相等的时候, 如果寻找左边界, 则 hi = mid
,如果寻找右边界, 则 lo = mid + 1
;