二分查找(1)文末二分模板

109 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第23天,点击查看活动详情

374. 猜数字大小

思路:

代码:

class Solution {
public:
    int guessNumber(int n) {
        int l = 1, r = n;
        while (l < r) {
            int mid = l + (r - l)/2;
            if (guess(mid) <= 0) r = mid;
            else l = mid + 1;
        }
        return r;
    }
};

278. 第一个错误的版本

思路:

代码:

class Solution {
public:
    int firstBadVersion(int n) {
        int l = 1, r = n;
        while (l < r) {
            int mid = l +(r - l) / 2;
            if (isBadVersion(mid)) r = mid;
            else l = mid + 1;
        }
        return r;
    }
};

274. H 指数

思路:

代码:

class Solution {
public:
    int hIndex(vector<int>& citations) {
        sort (citations.begin(), citations.end());

        // if (citations.size() == 1 && citations[0] == 0) return 0;
        int h = 0, ans = 0;
        for (int i = citations.size() - 1; i >= 0; i--) {
            if (citations[i] >= citations.size() - i) {
                h = citations.size() - i;
            }
            ans = max(h, ans);
        }
        
        return ans;
    }
};

153. 寻找旋转排序数组中的最小值

思路:

代码:

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

154. 寻找旋转排序数组中的最小值 II

思路

代码:

class Solution {
public:
    int findMin(vector<int>& nums) {
        // 恢复二段性
        int n = nums.size();
        int left = 0,right = n - 1;
        while(left < right && nums[right] == nums[0]){
            right--;
        }
        // 找到旋转点
        while (left < right){
            int mid = left + right + 1 >> 1;
            if(nums[mid] >= nums[0]){
                left = mid;
            } else{
                right = mid - 1;
            }
        }
        return right + 1 < n ? nums[right + 1] : nums[0];
    }
};

模板一:

区间左侧,找最小

{
    while (l < r)
    {
        int mid = (l + r)/2;
        if (nums[mid] >= target) r = mid;
        else l = mid + 1;
    }
    return l;
}


模板二:

区间右侧,找最大

int bsearch_2(int l, int r)
{
    while (l < r)
    {
        int mid = ( l + r + 1 ) /2;
        if (nums[mid] <= target) l = mid;
        else r = mid - 1;
    }
    return l;
}

while循环结束条件是l >= r,但为什么二分结束时我们优先取r而不是l?

二分的while循环的结束条件是l>=r,所以在循环结束时l有可能会大于r,此时就可能导致越界,因此,基本上二分问题优先取r都不会翻车。