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

98 阅读1分钟

前言

一个本硕双非的小菜鸡,备战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)。