Skip to content

【二分】供暖器半径

供暖器

冬季已经来临。 你的任务是设计一个有固定加热半径的供暖器向所有房屋供暖。

在加热器的加热半径范围内的每个房屋都可以获得供暖。

现在,给出位于一条水平线上的房屋 houses 和供暖器 heaters 的位置,请你找出并返回可以覆盖所有房屋的最小加热半径。

说明:所有供暖器都遵循你的半径标准,加热的半径也一样。

二分搜索半径

最开始的想法,能否覆盖随半径是单调的,但这样在每次循环中仍需要搜索下一个没被覆盖的房子,所以最终时间复杂度是\(O(n\log^2n)\)

所以并不是能二分就一定二分...下面的贪心更简单。

class Solution {
public:
    int findRadius(vector<int>& houses, vector<int>& heaters) {
        sort(houses.begin(), houses.end());
        sort(heaters.begin(), heaters.end());
        // O(nlogn)
        auto check = [&](int m) {
            int next = 0;
            for (int i = 0; i < heaters.size(); i++) {
                int h = heaters[i];
                if (h - m > houses[next]) return false;
                next = upper_bound(houses.begin(), houses.end(), h + m) - houses.begin();
                if (next == houses.size()) return true;
            }
            return false;
        };
        // O(nlog^2n)
        int l = 0, r = max(houses.back(), heaters.back()) - houses[0] + 1;
        while (l <= r) {
            int m = (l + r) / 2;
            if (check(m)) r = m - 1;
            else l = m + 1;
        }
        return l;
    }
};

贪心,记录每个房子的最近供暖器

更直接的做法,直接遍历房子,同时记录最近的供暖器即可,时间复杂度\(O(n\log n)\)(排序)

class Solution {
public:
    int findRadius(vector<int>& houses, vector<int>& heaters) {
        sort(houses.begin(),houses.end());
        sort(heaters.begin(),heaters.end());
        int ans = 0;
        int h = 0;
        // O(n)
        for (int i=0;i<houses.size();i++){
            while (h + 1 < heaters.size() && 
                   abs(houses[i] - heaters[h]) >= abs(houses[i] - heaters[h + 1])) h++;
            ans = max(ans,abs(houses[i]-heaters[h]));
        }
        return ans;
    }
};