《从零开始的の二分查找の生活》

二分查找

二分查找是背板子的问题,但是经常出现细节处理很烦的问题,今天在b站发现了一个特别神奇的二分新思想。

二分查找

思想

在这里插入图片描述
伪代码如上,在端点定义时这么定义,可以在l/r的处理上变得很方便,返回时根据需求即可,如此骚操作,拿题来试一下:

704.二分查找 - 力扣

我的代码不一定是最好的,本题是二分查找板子题,让我们来看一哈板子题是怎么写的:

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

很舒服的代码,找不到目标的话,直接在结尾特判一下就好了,基本思想跟二分是一模一样的。

中等难度

35.搜索插入位置 - 力扣

也是一道简单题,这个直接返回r即可

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

162.寻找峰值 - 力扣

num[i] < nums[i+1] && nums[i] > nums[i-1] 说明峰值在其右边;

num[i] > nums[i+1] && nums[i] < nums[i-1] 说明峰值在其左边;

num[i] < nums[i+1] && nums[i] < nums[i-1] 说明在谷底,下一步往左边和右边都可以

简单借鉴了一下别人的代码,这道题需要特殊处理一下当数组只有很少数个的时候的情况

class Solution {
public:
    int findPeakElement(vector<int>& nums) {
        if(nums.size() <= 1)
            return 0;
        int l = -1;
        int r = nums.size();
        while(l + 1 != r){
            int mid = l + (r - l) / 2;

            int lvalue = mid - 1 < 0 ? -2147483648 : nums[mid - 1];
            int rvalue = mid + 1 >= nums.size() ? -2147483648 : nums[mid + 1]; 

            if(nums[mid] >= lvalue && nums[mid] <= rvalue){
                l = mid;
            }else{
                r = mid;
            }
        }
        return r;
    }
};

力扣的测试样例有一组数据是[-2147483648,-2147483647],所以把lvalue和rlvalue的值设置为int的最小值。

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

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        int l1 = -1;
        int r1 = nums.size();
        while(l1 + 1 != r1){
            int mid = l1 + (r1 - l1) / 2;
            if(nums[mid] < target){
                l1 = mid;
            }else{
                r1 = mid;
            }
        }
        int r2 = r1;
        if (r1 == nums.size() || nums[r1] != target)
                return vector<int>{-1,-1};
        
        while(r2 + 1 < nums.size() && nums[r2 + 1] == target)
            r2++;

        return vector<int>{r1,r2};
    }
};

代码太水了,但是需要注意的是,在第一次二分查找,把小于target的值直接全部放到左边,然后右指针就是要找的第一个数组下标,然后向后循环找到最后一个target即可,主语吼,最后一个while循环,条件那么写就行,然后就是,需要处理一下数组里面没有或者找完以后发现没有target时需要返回[1,-1]

74.搜索二维矩阵 - 力扣

class Solution {
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        int m = matrix.size(), n = matrix[0].size();
        if(matrix[m - 1][n - 1] < target) return false;
        int l = -1;
        int r = m * n;
        while(l + 1 != r){
            int mid = l + (r - l) / 2;
            int i = mid / n;
            int j = mid % n;
            if(matrix[i][j] < target){
                l = mid;
            }else{
                r = mid;
            }
        }
        return matrix[r / n][r % n] == target;
    }
};

这道题直接把二维矩阵转化成一维来看然后二分即可。
因为数组边界已知,所以在转化后的一维下标想得到原来的二维下标,把 mid 除以 n(列数),即可得到行数下标,把 mid 作 n (列数)的余数,即可得到列数,然后便可得到二维下标,判断是否小于target即可,最后找到的r便是target的一维下标,然后我们对照一下二维下标的数组中的值是否等于target然后输出即可。

240.搜索二维矩阵 II - 力扣

这个题跟上一道不太一样,使用这种二分搜索的话,或者像官网的二分搜索的话,较繁琐,而且也不能将其转换为一维数组进行思索,所以使用最简单的搜索,从右上角搜索,这样子只需要查找一行和一列就可以了

class Solution {
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        int m = matrix.size(), n = matrix[0].size();
        int i = 0, j = n - 1;
        while(i < m && j >= 0){
            if(matrix[i][j] > target){
                j--;
            }else if(matrix[i][j] < target){
                i++;
            }else{
                return true;
            }
        }
        return false;
    }
};

因为数组的特点是,每一个元素的右侧或者下侧的元素都比它大,所以可以从右上角进行向下查找搜索。
这里需要注意一下 while 的判断条件,j 是可以等于零的。

目前就写了这些题,后续再加吧~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值