代码随想录一刷打卡——二分查找

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

一个本硕双非的小菜鸡,备战24年秋招,计划刷完卡子哥的刷题计划,加油!
推荐一手卡子哥的刷题网站,感谢卡子哥。代码随想录

一、704.二分查找

力扣704二分查找
Time / Space:时间 32 ms,内存 27 MB
Note:对于target的边界问题要注意,要理解记忆。
以下是 target 在[left, right]中

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size() - 1;

        while (left <= right) {
            int middle = left + ((right - left) / 2);
            if (nums[middle] > target) {
                right = middle - 1;
            } else if (nums[middle] < target) {
                left = middle + 1;
            } else {
                return middle;
            }
        }
        return -1;
    }
};

二、35. 搜索插入位置

力扣35搜索插入位置

Time / Space:时间4 ms击败78.85%,内存9.4 MB击败30.30%
Note:官方题解下munpf大佬关于为何返回的是left解释的很好,以下是原回答:
不需要ans变量,最后直接返回left就可以了,根据if的判断条件,left左边的值一直保持小于target,right右边的值一直保持大于等于target,而且left最终一定等于right+1,这么一来,循环结束后,在left和right之间画一条竖线,恰好可以把数组分为两部分:left左边的部分和right右边的部分,而且left左边的部分全部小于target,并以right结尾;right右边的部分全部大于等于target,并以left为首。所以最终答案一定在left的位置。
以下是我的理解:匹配不到的倒数第二步会出现middle = left(此时left与right差值为1),执行left + 1,最终会出现left = right,然后执行right - 1.所以如果我们想要较大的那个位置,应该返回left。

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size() - 1;

        while (left <= right) {
            int middle = left + ((right - left) / 2);
            if (nums[middle] > target) {
                right = middle - 1;
            } else if (nums[middle] < target) {
                left = middle + 1;
            } else {
                return middle;
            }
        }
        return left;
    }
};

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

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

Time / Space:时间16 ms,内存13.2 MB
Note:官方题解比较通俗易懂,说白了就是把二分查找当作一个函数来调用。

class Solution {
public:
    int binarySearch(vector<int>& nums, int target, bool lower) {
        int left = 0;
        int right = nums.size() - 1;
        int ans = nums.size();

        while(left <= right) {
            int middle = left + ((right - left) / 2);
            if (nums[middle] > target || (lower && nums[middle] >= target)) {
                right = middle - 1;
                ans = middle;
            } else {
                left = middle + 1;
            }
        }
        return ans;
    }
    vector<int> searchRange(vector<int>& nums, int target) {
        int leftIndex = binarySearch(nums, target, true);
        int rightIndex = binarySearch(nums, target, false) - 1;

        if(leftIndex <= rightIndex && rightIndex < nums.size() && nums[leftIndex] == target && nums[rightIndex] == target) {
            return vector<int>{leftIndex, rightIndex};
        }
        return vector<int>{-1, -1};
    }
};

四、367. 有效的完全平方数

367. 有效的完全平方数

Time / Space:时间4 ms击败25.44%,内存5.8 MB击败31.10%
Note:两个middle相乘会超过int,记着用long

class Solution {
public:
    bool isPerfectSquare(int num) {
        int leftIndex = 0;
        int rightIndex = num;

        while (leftIndex <= rightIndex) {
            long middle = leftIndex + ((rightIndex - leftIndex) / 2);
            if (middle * middle > num) {
                rightIndex = middle - 1;
            } else if (middle * middle < num) {
                leftIndex = middle + 1;
            } else {
                return true;
            }
        }
        return false;
    }
};

总结

写二分法经常写乱,主要是因为对区间的定义没有想清楚,区间的定义就是不变量。要在二分查找的过程中,保持不变量,就是在while寻找中每一次边界的处理都要坚持根据区间的定义来操作,这就是循环不变量规则。
写二分法,区间的定义一般为两种,左闭右闭即[left, right],或者左闭右开即[left, right)。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

努力找工作的小菜鸡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值