代码随想录二分查找

704二分查找

在这里插入图片描述

一,左闭右闭[left, right]
左闭右闭,说明二者最后会出现相等的情况,不能忽视left == right的情况。

//值得注意的点
1.right = nums.size()-1;
2.while(left <= right)
3. right = middle - 1;

完整版

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int l = 0,r = nums.size()-1;
        while(l <= r){
            int mid = l + (r-l)/2;
            if(nums[mid] == target){
                return mid;
            }else if(nums[mid] > target){
                r = mid - 1;
            }else{
                l = mid +1;
            }
        }
        return -1;
    }
};

二,左闭右开[left, right)
右开说明不会出现left == right的情况

//值得注意的点
1.right = nums.size();
2.while(left < right)
3. right = middle;
class Solution {
public:
    int search(vector<int>& nums, int target) {
        int l = 0,r = nums.size();
        while(l < r){
            int mid = l + (r-l)/2;
            if(nums[mid] == target){
                return mid;
            }else if(nums[mid] > target){
                r = mid;
            }else{
                l = mid +1;
            }
        }
        return -1;
    }
};

35.搜索插入位置

在这里插入图片描述
本题为标准的二分查找,左闭右闭区间返回l
因为左闭右闭区间最后的l和r是l在r的右边即l>r而本题目返回的正好是要求返回比target大的最小的那个数,因此为l,因此l为比target大的最小的那个数,r为比target小的那个最大的数

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int l = 0,r = nums.size()-1;
        while(l <= r){
            int mid = l + (r -l)/2;
            if(nums[mid] == target){
                return mid;
            }else if(nums[mid] > target){
                r = mid -1;
            }else{
                l  = mid + 1;
            }
        }
        return l;//返回左区间
    }
};

左闭右开区间最后l==r所以l和r都指向了比target大的最小的那个数,因此返回l还是r都可以

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int l = 0,r = nums.size()-1;
        while(l <= r){
            int mid = l + (r -l)/2;
            if(nums[mid] == target){
                return mid;
            }else if(nums[mid] > target){
                r = mid -1;
            }else{
                l  = mid + 1;
            }
        }
        return l;//return r;
    }
};

实战中,最后返回r还是l可以自己尝试提交确定。

下面是重要的二分查找的边界控制

1.在一段重复数字中求其右边界
比如:数组[1,2,4,4,4,5]的右边界为5
使用左闭右闭区间解法,要求右边界,则在nums[mid] =target 时移动left,利用left = mid +1一直移动left就把left移动到了右边界。而left = mid +1语句是在nums[mid]<target时进行的 ,即就是在nums[mid]<=target时进行left = mid +1 操作并不断赋值给r_board即可以找到右边界r_board

int getr_board(vector<int>& nums, int target){
        int l=0,r = nums.size()-1;
        int r_board = -2;//右边界没被赋值
        while(l<=r){
            int mid = l + (r-l)/2;
            if(nums[mid] > target){
                r  = mid-1;
            }else{
                l = mid + 1;
                r_board = l;
            }
        }
        return r_board;
    }

同理
2.在一段重复数字中求其左边界

int getl_board(vector<int>& nums, int target){
        int l=0,r = nums.size()-1;
        int l_board = -2;
        while(l<=r){
            int mid = l + (r-l)/2;
            if(nums[mid] >= target){
                r  = mid-1;
                l_board = r;
            }else{
                l = mid+1;
            }
        }
        return l_board;
    }

下面的题目都用了这样的思想
34. 在排序数组中查找元素的第一个和最后一个位置
在这里插入图片描述
本题目分为3种情况考虑
1.target在nums数组的左/右边,即target不在nums数组的范围内
2.target在数组范围内但数组内不存在target
3.数组内存在target

class Solution {
public:
    int getr_board(vector<int>& nums, int target){
        int l=0,r = nums.size()-1;
        int r_board = -2;
        while(l<=r){
            int mid = l + (r-l)/2;
            if(nums[mid] > target){
                r  = mid-1;
            }else{
                l = mid+1;
                r_board = l;
            }
        }
        return r_board;
    }
    int getl_board(vector<int>& nums, int target){
        int l=0,r = nums.size()-1;
        int l_board = -2;
        while(l<=r){
            int mid = l + (r-l)/2;
            if(nums[mid] >= target){
                r  = mid-1;
                l_board = r;
            }else{
                l = mid+1;
            }
        }
        return l_board;
    }
    vector<int> searchRange(vector<int>& nums, int target) {
        int l_board = getl_board(nums,target);
        int r_board = getr_board(nums,target);
        
        //情况1:target在nums数组的左/右边
        if(l_board == -2 || r_board == -2){
            return {-1,-1};
        }
        //情况3:存在target
        if(r_board - l_board > 1){//左右边界之差大于1说明至少有1个target在数组中
            return {l_board+1,r_board-1};
        }
        //情况2:target在数组范围内但数组内不存在target
        return {-1,-1};
    }
};

69. x 的平方根

在这里插入图片描述
本题相当于求解k*k<=x的比k小的最大的整数

class Solution {
public:
    int mySqrt(int x) {
        int l = 0 , r = x, ans = -1;
        while(l<=r){
            int mid = l + (r-l)/2;
            if((long long)mid * mid <= x){
                l = mid + 1;
                ans = l;
            }else{
                r = mid - 1;
            }
        }
        return ans -1;
    }
};

367. 有效的完全平方数

在这里插入图片描述

class Solution {
public:
    bool isPerfectSquare(int num) {
        int l = 0,r= num,ans = -1;
        while(l<= r){
            int mid = l + (r-l)/2;
            if((long long)mid * mid <= num){
                l = mid + 1;
                ans = mid;
            }else{
                r = mid - 1;
            }
        }
        //判断两个边界是否满足条件即可求解
        if(ans * ans == num){
            return true;
        }
        if((ans-1)*(ans-1) == num){
            return true;
        }
        return false;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值