LeetCode 475. Heaters
冬季已经来临。 你的任务是设计一个有固定加热半径的供暖器向所有房屋供暖。
在加热器的加热半径范围内的每个房屋都可以获得供暖。
现在,给出位于一条水平线上的房屋 houses 和供暖器 heaters 的位置,请你找出并返回可以覆盖所有房屋的最小加热半径。
说明:所有供暖器都遵循你的半径标准,加热的半径也一样。
示例 1:
输入: houses = [1,2,3], heaters = [2]
输出: 1
解释: 仅在位置2上有一个供暖器。如果我们将加热半径设为1,那么所有房屋就都能得到供暖。
示例 2:
输入: houses = [1,2,3,4], heaters = [1,4]
输出: 1
解释: 在位置1, 4上有两个供暖器。我们需要将加热半径设为1,这样所有房屋就都能得到供暖。
示例 3:
输入: houses = [1,5], heaters = [2]
输出: 3
提示:
1 <= houses.length, heaters.length <= 3 * 1041 <= houses[i], heaters[i] <= 109
算法1
(二分答案) O(nlogn+mlogm+(n+m)logL)
将房屋和暖气的位置分别从小到大排序。
假设得到了加热半径 r,即可在 O(n+m)的时间内,判断是否所有的房屋都得到了暖气,具体为,逐一枚举房屋,然后判断是否有暖气覆盖,由于房屋和暖气的坐标都是单调的,所以第 i+1 个房屋不会使用坐标小于第 i 个房屋的暖气位置。
加热半径也是单调的,故可以使用二分来加速寻找最小的半径。
时间复杂度
排序的时间复杂度为 O(nlogn+mlogm),二分判定的时间复杂度为 O((n+m)logL),其中L为最大房屋或暖气的坐标。
空间复杂度
仅需要常数的额外空间。
C++ 代码
class Solution {
public:
bool check(int r, const vector<int>& houses, const vector<int>& heaters) {
int n = heaters.size();
for (int i = 0, j = 0; i < houses.size(); i++) {
while (j < n && abs(houses[i] - heaters[j]) > r)
j++;
if (j == n)
return false;
}
return true;
}
int findRadius(vector<int>& houses, vector<int>& heaters) {
sort(houses.begin(), houses.end());
sort(heaters.begin(), heaters.end());
if (houses.size() == 0)
return 0;
int l = 0, r = max(*houses.rbegin(), *heaters.rbegin());
while (l < r) {
int mid = (l + r) >> 1;
if (check(mid, houses, heaters))
r = mid;
else
l = mid + 1;
}
return l;
}
};
算法2
(贪心) O(nlogn+mlogm)
将房屋和暖气的位置分别从小到大排序。
逐一枚举每个房屋,对于房屋 i,他使用暖气必定是距离他左右(如果有)最近的两个之一,由于我们已经对坐标进行了排序,所以这个过程如算法 1 一样是单调的。
按照 2 的过程,随时更新半径的最大值r即可。
时间复杂度
排序的时间复杂度为 O(nlogn+mlogm),然后是线性扫描,每个位置最多被遍历一次,时间复杂度为 O(n+m),故总时间复杂度为 O(nlogn+mlogm)。
空间复杂度
仅需要常数的额外空间。
C++ 代码
class Solution {
public:
int findRadius(vector<int>& houses, vector<int>& heaters) {
int n = heaters.size();
sort(houses.begin(), houses.end());
sort(heaters.begin(), heaters.end());
int r = 0;
for (int i = 0, j = 0; i < houses.size(); i++) {
if (abs(houses[i] - heaters[j]) > r) {
while (j < n && heaters[j] < houses[i])
j++;
if (j == n) {
r = max(r, houses[i] - heaters[j - 1]);
j--;
} else if (j == 0) {
r = max(r, heaters[j] - houses[i]);
} else {
if (houses[i] - heaters[j - 1] < heaters[j] - houses[i]) {
r = max(r, houses[i] - heaters[j - 1]);
j--;
} else
r = max(r, heaters[j] - houses[i]);
}
}
}
return r;
}
};