五月集训(第09天)—二分查找

二分查找

1. 35. 搜索插入位置

    思路:
        对每个数平方后排序即可

class Solution {
public:
    bool check(int ans, int target) {
        if (ans >= target) return true;
        return false;
    }

    int Binary_Search(int target, vector<int>& nums) {
        int l = 0, r = nums.size() - 1, mid;
        int ans = r + 1; // 初值考虑边界情况
        while (l <= r) {
            mid = l + (( r - l) >> 1);
            if (check(nums[mid], target)) {
                // 找到目标值下标ans,或大于目标值的第一个下标
                ans = mid;
                r = mid - 1;
            } else {
                l = mid + 1;
            }
            //cout << "ans = "<< mid << endl;
        }
        return ans;
    }

    int searchInsert(vector<int>& nums, int target) {
        return Binary_Search(target, nums);
    }
};

没想到啊没想到,一道模板题裂开了这么多发,原来是没有考虑查找的边界情况,记住了。
在这里插入图片描述

2. 704. 二分查找

    思路:
        找等于target的下标或者大于target的第一个下标。判断如果没找到,则返回-1,否则返回结果。

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int n = nums.size();
        int l = 0, r = n - 1, mid, ans = n - 1;
        while (l <= r) {
            mid = l + ((r - l) >> 1);
            if (nums[mid] >= target) {
                // 等于target或者大于的第一个下标
                ans = mid;
                r = mid - 1;
            } else {
                l = mid + 1;
            }
        }
        return (nums[ans] != target) ? -1 : ans;
    }
};

3. 剑指 Offer 53 - I. 在排序数组中查找数字 I

    思路:
        思路(1):是找到目标值,然后向后遍历,如果是整个数组都是target的极端情况下,时间复杂度为$O(n)$。
        思路(2):是利用两套二分方案,分别找到目标值的最左端和最右端,时间复杂度是$O(logn)$不过代码有点长
        思路(3):看到英雄哥的思路,妙啊,由于我的check方式获取的是目标值下标或者大于目标值的第一个下标,所以直接找targettarget+1的下标做差即可,时间复杂度$O(logn)$。


class Solution {
public:
    int Binary_Search(int target, int n, vector<int> &nums) {
        int l = 0, r = n - 1, mid, ans = n;
        while (l <= r) {
            mid = l + ((r - l) >> 1);
            if (nums[mid] >= target) {
                ans = mid;
                r = mid - 1;
            } else {
                l = mid + 1;
            }
        }
        return ans;
    }

    int search(vector<int>& nums, int target) {
        int n = nums.size();
        int ans = Binary_Search(target, n, nums);
        return (ans == n || nums[ans] != target) ? 0 : Binary_Search(target + 1, n, nums) - ans;
    }
};

4. 911. 在线选举

    题目理解补充:
        [0,1,1,0,0,1,0], [0,5,10,15,20,25,30]

        上面的输入表示:

        第 0 分钟投给 0 号; 第 5 分钟投给 1 号; 第 10 分钟投给 1 号; 第 15 分钟投给 0 号; 第 20 分钟投给 0 号; 第 25 分钟投给 1 号; 第 30 分钟投给 0 号;

    思路:
         step1: 预处理出每个时刻内的winner

         step2: 二分查找t时刻对应的下标,索引得到winner

#define maxn 5001

typedef struct {
    int p[maxn], t[maxn], win[maxn];
    int cnt[maxn];
    int size;
} TopVotedCandidate;

// 预处理每个时刻内的winner
TopVotedCandidate* topVotedCandidateCreate(int* persons, int personsSize, int* times, int timesSize) {
	// 申请空间
    TopVotedCandidate *obj = (TopVotedCandidate *)malloc(sizeof(TopVotedCandidate));
    // 初始化数组
    memset(obj->cnt, 0, sizeof(obj->cnt));
    int preMaxPerson = -1;
    obj->size = personsSize;
    for (int i = 0; i < personsSize; i++) {
        obj->p[i] = persons[i];
        obj->t[i] = times[i];
        obj->cnt[ obj->p[i] ]++;
        if (preMaxPerson == -1 || obj->cnt[preMaxPerson] <= obj->cnt[ obj->p[i] ]) {
            preMaxPerson = obj->p[i];
        }
        obj->win[i] = preMaxPerson;
    }
    return obj;
}

// 二分查找时间t对应下标
int topVotedCandidateQ(TopVotedCandidate* obj, int t) {
    int l = 0, r = obj->size - 1, mid, ans = 0;
    while (l <= r) {
        mid = l + ((r - l) >> 1);
        if (obj->t[mid] <= t) {
            // 找到时间t的下标或者小于t的第一个下标
            ans = mid;
            l = mid + 1;
        } else {
            r = mid - 1;
        }
    }
    return obj->win[ans];
}

// 释放申请的空间
void topVotedCandidateFree(TopVotedCandidate* obj) {
    free(obj);
}

/**
 * Your TopVotedCandidate struct will be instantiated and called as such:
 * TopVotedCandidate* obj = topVotedCandidateCreate(persons, personsSize, times, timesSize);
 * int param_1 = topVotedCandidateQ(obj, t);
 
 * topVotedCandidateFree(obj);
*/

5. 1552. 两球之间的磁力

    思路:
        经典二分,一个二分框架,一个check()函数。寻找最小磁力的最大值,二分答案,就要直接找答案,于是直接先二分一个最小磁力的最大值,然后check在这个值的情况下,能否放下所有的m个球,如果可以,再去找更大的值,如果不可以,去找小一些的值。

class Solution {
public:
    bool check(int ans, int n, int m, vector<int> &position) {
        int pre = position[0];
        m--;
        for (int i = 1; i < n; i++) {
            if (!m) return true;
            if (position[i] - pre >= ans) {
                --m;
                pre = position[i];
            }
            if (!m) return true;
        }
        return false;
    }

    int maxDistance(vector<int>& position, int m) {
        int n = position.size();
        // 二分模板
        int l = 0, r = 1e9 + 5, mid, ans;
        sort(position.begin(), position.end());
        while (l <= r) {
            mid = l + ((r - l) >> 1);
            if (check(mid, n, m, position)) {
                ans = mid;
                l = mid + 1;
            } else {
                r = mid - 1;
            }
        }
        return ans;
    }
};
posted @ 2022-05-09 08:27  番茄元  阅读(8)  评论(0)    收藏  举报