006_二分查找

二分查找不难,但是很容易出错

(easy 704. 二分查找)
📌1 递归

递归要注意target的值在哪个范围, 如果target小于最小值或者大于最大值

📌2 循环

class Solution {
public:
    int search(vector<int>& nums, int target) {
        //左右指针采取 双闭区间
        int left = 0;
        int right = nums.size() - 1;	//注意
        while(left<=right)	//注意 明确搜索空间这个概念.如果是双闭区间,[left,left]非空,要再循环一次;如果左闭右开, [left,left)是空,<就行了
        {
            int mid = (left+right)/2;
            if(nums[mid]>target) right = mid - 1;	//注意 这里的关键就是下一个搜索区间也是 双闭区间
            else if(nums[mid]<target) left = mid + 1;
            else return mid;
        }
        return -1;
    }
};

📌总结

  1. 尾递归都可以用循环解决
  2. 如果采取 双闭区间, 上例中的这个num[mid], 奇数就是中间那个, 偶数就是中间两个靠左边那个

📌 两种区间
上例假设 nums.size() = n 用索引取值的话就是取到: 0, 1, ... , n-1
我们通常使用以下两种方法来表示这个取值范围:

1.双闭区间[0,n-1],即两个边界都包含自身;在此方法下,区间 [0,0] 仍包含个元素;(建议使用)
2.左闭右开[0,n),即左边界包含自身、右边界不包含自身;在此方法下,区间 [0,0) 不包含元素.

C++迭代器是使用左闭右开区间 [) 的. 比如erase(), 去除一个左闭右开区间, 返回右边的元素.

在“双闭区间”表示法中,由于对左右两边界的定义相同,因此缩小区间的i和j的处理方法也是对称的,这样更不容易出错。因此,建议采用“双闭区间”的写法。(Hello 算法)

34. 在排序数组中查找元素的第一个和最后一个位置

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        vector<int> res{-1,-1};
        if(nums.size()==0)  return res;

        //开始位置
        int left=0;int right=nums.size()-1;
        while(left<=right)
        {
            int mid = left+(right-left)/2;
            if(nums[mid]<target)  left=mid+1;
            else  right=mid-1; //继续锁定左边界
        }
        if(left==nums.size())  res[0]=-1;
        else res[0]= nums[left]==target?left:-1;

        //结束位置
        left=0;right=nums.size()-1;
        while(left<=right)
        {
            int mid = left+(right-left)/2;
            if(nums[mid]<target)  left=mid+1;
            else  left=mid+1; //继续锁定右边界
        }
        if(left-1<0)  res[1]=-1;
        else res[1]=nums[left-1]==target?left-1:-1;

        return res;
    }
};

注意越界的判断

posted @ 2023-04-11 22:45  无形深空  阅读(11)  评论(0编辑  收藏  举报