二分查找算法简介
特点
细节多,最容易写出死循环的算法
学习侧重点
- 算法原理
二分查找算法不仅在数组有序的时候可以用,数组无序的时候同样可以用,其实最准确的说法是:只要我们可以发现数组中的规律就能够使用二分查找. - 模版
朴素的二分模版
查找左边界的二分模版
查找右边界的二分模版
704. 二分查找
题目链接: leetcode704.二分查找
题目解析
算法原理
在一个数组中找一个点,用这个点和target作比较后划分出两个区域,根据规律我们可以选择性的去舍去一个区域,然后在另一个区域去寻找.,所以题目中,有"二段性"就可以用二分查找算法.
下面的点都有可能被选而和target值作比较,那我们到底如何选择呢?其实本质上,我们只要找到的点可以把区间分成两部分就可以了.
我们有非常多的方案来选择划分点,但其实我们还是要选择中间的那个点来划分,这就涉及到我们概率学中的问题:求数学期望.在上面众多方案中,我们选择中间的那个点来划分时间复杂度是最好的.
朴素版本的二分查找:
细节问题:
- 循环结束的条件:left > right
- 时间复杂度
编写代码
class Solution {
public int search(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{
return mid;
}
}
return -1;
}
}
朴素二分模版
34. 在排序数组中查找元素的第一个和最后一个位置
题目链接: leetcode34. 在排序数组中查找元素的第一个和最后一个位置
题目解析
算法原理
细节处理:
- 循环条件:left < right
- 求中点的操作
编写代码
class Solution {
public int[] searchRange(int[] nums, int target)
{
int[] ret = new int[2];
ret[0] = ret[1] = -1;
//处理边界情况
if(nums.length == 0) return ret;
// 1.二分左端点
int left = 0, right = nums.length - 1;
while(left < right)
{
int mid = left + (right-left)/2;
if(nums[mid] < target) left = mid + 1;
else right = mid;
}
//判断是否有结果
if(nums[left] != target) return ret;
else ret[0] = right;
// 2.二分右端点
left = 0; right = nums.length - 1;
while(left < right)
{
int mid = left + (right-left+1)/2;
if(nums[mid] <= target) left = mid;
else right = mid - 1;
}
ret[1] = left;
return ret;
}
}