[LeetCode] 475. Heaters
Winter is coming! During the contest, your first job is to design a standard heater with a fixed warm radius to warm all the houses.
Every house can be warmed, as long as the house is within the heater's warm radius range.
Given the positions of houses
and heaters
on a horizontal line, return the minimum radius standard of heaters so that those heaters could cover all houses.
Notice that all the heaters
follow your radius standard, and the warm radius will the same.
Example 1:
Input: houses = [1,2,3], heaters = [2] Output: 1 Explanation: The only heater was placed in the position 2, and if we use the radius 1 standard, then all the houses can be warmed.
Example 2:
Input: houses = [1,2,3,4], heaters = [1,4] Output: 1 Explanation: The two heater was placed in the position 1 and 4. We need to use radius 1 standard, then all the houses can be warmed.
Example 3:
Input: houses = [1,5], heaters = [2] Output: 3
Constraints:
1 <= houses.length, heaters.length <= 3 * 104
1 <= houses[i], heaters[i] <= 109
供暖器。
冬季已经来临。 你的任务是设计一个有固定加热半径的供暖器向所有房屋供暖。
在加热器的加热半径范围内的每个房屋都可以获得供暖。
现在,给出位于一条水平线上的房屋 houses 和供暖器 heaters 的位置,请你找出并返回可以覆盖所有房屋的最小加热半径。
说明:所有供暖器都遵循你的半径标准,加热的半径也一样。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/heaters
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
这道题同 LintCode 1219题。
这道题看似只有两个数组但是有多种做法,可以用双指针或二分法做。无论哪种做法,都需要对 heaters 数组进行排序。
首先是双指针的思路,两个指针是同向的,都是从左往右走。对于双指针的做法,需要对两个 input 数组都进行排序,这样当我们用两个指针去分别遍历 houses 数组和 heaters 数组的时候,对于每一个 house,我们要看到底是当前这个 heater 离得近还是下一个 heater 离得近,如果一直是下一个 heater 离得近则 heater 的指针一直往前走。
时间O(mn) - 极端情况
空间O(1)
Java实现
1 class Solution { 2 public int findRadius(int[] houses, int[] heaters) { 3 Arrays.sort(houses); 4 Arrays.sort(heaters); 5 int res = 0; 6 int i = 0; 7 for (int house : houses) { 8 int dist = Math.abs(house - heaters[i]); 9 // 如果下一个heater离得近,则i++ 10 while (i + 1 < heaters.length && Math.abs(house - heaters[i + 1]) <= Math.abs(house - heaters[i])) { 11 i++; 12 dist = Math.min(dist, Math.abs(house - heaters[i])); 13 } 14 res = Math.max(res, dist); 15 } 16 return res; 17 } 18 }
这里我再提供一种 treeset 的实现,其实背后的思路也是双指针。
时间O(nlogn) - treeset内部的排序
空间O(n)
Java实现
1 class Solution { 2 public int findRadius(int[] houses, int[] heaters) { 3 TreeSet<Integer> set = new TreeSet<>(); 4 for (int heater : heaters) { 5 set.add(heater); 6 } 7 8 int res = 0; 9 for (int house : houses) { 10 int dist1 = set.ceiling(house) == null ? Integer.MAX_VALUE : set.ceiling(house) - house; 11 int dist2 = set.floor(house) == null ? Integer.MAX_VALUE : house - set.floor(house); 12 res = Math.max(res, Math.min(dist1, dist2)); 13 } 14 return res; 15 } 16 }
另一种思路是二分法。这里我们还是需要对 heaters 数组排序。对于每个 house,我们需要在有序数组 heaters 里用二分法找到一个离当前 house 距离最近的 heater。
时间O(nlogn)
空间O(1)
Java实现
1 class Solution { 2 public int findRadius(int[] houses, int[] heaters) { 3 Arrays.sort(heaters); 4 int res = 0; 5 for (int house : houses) { 6 int dist = helper(house, heaters); 7 res = Math.max(res, dist); 8 } 9 return res; 10 } 11 12 private int helper(int house, int[] heaters) { 13 int start = 0; 14 int end = heaters.length - 1; 15 int dist1 = Integer.MAX_VALUE; 16 int dist2 = Integer.MAX_VALUE; 17 while (start <= end) { 18 int mid = start + (end - start) / 2; 19 int heater = heaters[mid]; 20 if (heater == house) { 21 return 0; 22 } else if (heater > house) { 23 dist2 = heater - house; 24 end = mid - 1; 25 } else { 26 dist1 = house - heater; 27 start = mid + 1; 28 } 29 } 30 return Math.min(dist1, dist2); 31 } 32 }