二分供暖器
Posted FatalFlower
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二分供暖器相关的知识,希望对你有一定的参考价值。
问题描述
给出位于一条水平线上的房屋 \\(houses\\) 和供暖器 \\(heaters\\) 的位置,请找出并返回可以覆盖所有房屋的最小加热半径。所有供暖器都遵循你的半径标准,加热的半径也一样
比如,对于输入的 \\(house=[1, 5]\\),\\(heaters=[2]\\),那么至少需要使得供暖器的最小覆盖半径为 3 才能使得所有\\(house\\) 都能够被供暖器覆盖
数据范围:
-
\\(1 <= houses.length, heaters.length <= 3 * 10^4\\)
-
\\(1 <= houses[i], heaters[i] <= 10^9\\)
解决思路
由题目描述可知,本题具备的二分性:
- 如果供暖器的覆盖半径足够大,那么肯定能够将所有的房子都覆盖
- 如果供暖器的半径过小,那么肯定存在房子无法被覆盖
可以考虑通过二分的方式来求得最小的覆盖半径。二分的最小值为 0,即每个房子都有自己的供暖器,此时就不再需要覆盖半径;二分的最大值为 \\(houses\\) 的最大值,为了简单起见,可以将最大值设为 \\(10^9\\)
现在关键的地方在于如何检查给定的半径是否能够覆盖所有的房子。首先,需要对 \\(houses\\) 和 \\(heaters\\) 进行排序,然后再遍历 \\(houses\\) 的每个元素,找到在当前半径的条件下能够覆盖该 \\(house\\) 的最小的供暖器,如果无法找到,那么说明无法覆盖该 \\(house\\)
实现
具体的实现如下:
class Solution
public int findRadius(int[] houses, int[] heaters)
Arrays.sort(houses);
Arrays.sort(heaters);
int lo = 0, hi = (int) 1e9;
// 注意二分的边界情况,这是一个细节性的问题
while (lo < hi)
int mid = lo + ((hi - lo) >> 1);
if (check(houses, heaters, mid)) hi = mid;
else lo = mid + 1;
return hi;
boolean check(int[] houses, int[] heaters, int x)
int n = houses.length, m = heaters.length;
/*
通过双指针的方式首先找到合适的供暖器 heaters[j],
然后再使用当前的覆盖半径检测是否能够覆盖该房子
*/
for (int i = 0, j = 0; i < n; ++i)
while (j < m && heaters[j] + x < houses[i]) ++j;
// j >= m 说明没有供暖器了
if (j < m && houses[i] >= heaters[j] - x && houses[i] <= heaters[j] + x)
continue;
return false;
return true;
时间复杂度:令 \\(n=house.length, m = heaters.length\\),排序带来 \\(O(nlog_2n) + O(mlog_2m)\\) 的时间复杂度,使用二分搜索带来的时间复杂度为 \\(O(nlog_210^9)\\) 总体时间复杂度为 \\(O(max(n, m)*log_210^9)\\)
空间复杂度:具体由排序算法带来的空间复杂度,在这里不做分析
参考:https://leetcode-cn.com/problems/heaters/solution/gong-shui-san-xie-er-fen-shuang-zhi-zhen-mys4/
以上是关于二分供暖器的主要内容,如果未能解决你的问题,请参考以下文章
leetcode 工作每日一题 475. 供暖器 (二分 stl)