475. Heaters
Winter is coming! Your first job during the contest is to design a standard heater with fixed warm radius to warm all the houses.
Now, you are given positions of houses and heaters on a horizontal line, find out minimum radius of heaters so that all houses could be covered by those heaters.
So, your input will be the positions of houses and heaters seperately, and your expected output will be the minimum radius standard of heaters.
Note:
- Numbers of houses and heaters you are given are non-negative and will not exceed 25000.
- Positions of houses and heaters you are given are non-negative and will not exceed 10^9.
- As long as a house is in the heaters' warm radius range, it can be warmed.
- All the heaters follow your radius standard and the warm radius will the same.
Example 1:
Input: [1,2,3],[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: [1,2,3,4],[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.
使用2个数组,house的左边和右边找到最近的取暖器,然后在左边和右边的取暖器中找出个最小半径。最后再在所有house的最小半径中,找出一个最大值,就可以保证所有house都能取暖了。坐标数组里保存的都是真实坐标+1,这样,0就可以表示house的左边或者右边没有取暖器了。
import java.util.Arrays;
public class Solution {
public int findRadius(int[] houses, int[] heaters) {
Arrays.sort(houses);
Arrays.sort(heaters);
int left = 0, right = heaters.length - 1;
int[] lefts = new int[houses.length];
int[] rights = new int[houses.length];
for (int i = 0; i < houses.length; i++) {
// 找到最近的左侧取暖器
while (left < heaters.length && heaters[left] <= houses[i]) {
// 这里可以储存为left+1,如果是0,就代表没有取暖器
lefts[i] = left + 1;
left++;
}
// 下次遍历的left值,是这次的left值
left = lefts[i] != 0 ? (lefts[i] - 1) : 0;
while (right >= left && heaters[right] >= houses[i]) {
rights[i] = right + 1;
right--;
}
right = heaters.length - 1;
}
int ret = 0;
for (int i = 0; i < houses.length; i++) {
int min = Integer.MAX_VALUE;
// 找到houses[i] 的最近取暖器
if (lefts[i] != 0) {
min = Math.min(houses[i] - heaters[lefts[i] - 1], min);
}
if (rights[i] != 0) {
min = Math.min(heaters[rights[i] - 1] - houses[i], min);
}
ret = Math.max(min, ret);
}
System.out.println(ret);
return ret;
}
}
使用二分查找,top discuss中的答案
这是Discuss中的top解法。先将取暖器数组排序,在遍历所有house,对每个house,在取暖器数组中进行binary search,如果命中,则说明取暖器位置和house位置重合,这个house的最小半径为0;如果没有命中,则使用返回的index,将index左边和右边的取暖器坐标与house坐标求差值,找出这个house最小半径。说白了,也是在查找house的最近左右取暖器
public int findRadius(int[] houses, int[] heaters) {
Arrays.sort(heaters);
int result = 0;
for (int house : houses) {
// 找不到返回-(low+1)
int index = Arrays.binarySearch(heaters, house);
if (index < 0) {
index = ~index;
// ~index是大于target 第一个的下标,有可能超出数组范围
int dist1 = index - 1 >= 0 ?
house - heaters[index - 1] : Integer.MAX_VALUE;
int dist2 = index < heaters.length ?
heaters[index] - house : Integer.MAX_VALUE;
// 找到离house的最近的取暖炉
int min = Math.min(dist1, dist2);
result = Math.max(result, min);
}
}
return result;
}