难度 中等
冬季已经来临。 你的任务是设计一个有固定加热半径的供暖器向所有房屋供暖。
在加热器的加热半径范围内的每个房屋都可以获得供暖。
现在,给出位于一条水平线上的房屋 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,这样所有房屋就都能得到供暖。
public int findRadius(int[] houses, int[] heaters) {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < heaters.length; i++) {
list.add(heaters[i]);
}
int[] nums = new int[houses.length];
Arrays.fill(nums,Integer.MAX_VALUE);
Arrays.sort(heaters);
for (int i = 0; i < houses.length; i++) {
//二分查找
int flag = find(houses[i],heaters);
if (flag < heaters.length - 1){
nums[i] = Math.min((Math.abs(heaters[flag] - houses[i])),(Math.abs(heaters[flag +1] - houses[i])));
}else {
nums[i] = Math.abs(heaters[flag] - houses[i]);
}
}
int max = nums[0];
for (int i = 0; i < nums.length; i++) {
if (max < nums[i]){
max = nums[i];
}
}
return max;
}
private int find(int house, int[] heaters) {
int left = 0;
int right = heaters.length -1;
int mid ;
while (left < right){
mid = (((right - left + 1) >> 1) + left);
if (heaters[mid] >= house){
right = mid - 1;
}else {
left = mid ;
}
}
return left;
}
这里使用二分查找寻找距离房间最近的供暖点
我写的时候遇见两个问题,好长时间没有用过二分查找,都是基于暴力求解
今天这个测试点过不了,所以就使用二分查找
第一个问题,我想找到距离房间右侧最近的供暖点(相等或者在房间右侧距离最近的,特殊情况下房间右侧没有供暖点,这样我们取得是,最右侧得供暖点,因为我会在正文中去判断这个供暖点是否是最右侧的值),所以我不想让,left = mid +1,这样可能取到距离房间最近的供暖点在左侧
刚开始写的时候:
private int find(int house, int[] heaters) {
int left = 0;
int right = heaters.length -1;
int mid ;
while (left < right){
mid = ((right - left) >> 1 + left);
if (heaters[mid] >= house){
right = mid - 1;
}else {
left = mid ;
}
}
return left;
}
这样当((right - left) >> 1 + left)等于奇数时也会在后面求余时,给省略掉,这样
int[] house = {1 , 2 , 3}; int[] heaters = {1 , 2 , 3};
这样的案例就会一直在二分查找循环中,出不来。
正解:(((right - left +1) >> 1) + left)
第二个问题:
>> 的优先级 小于 + ,刚开始一直 (2 - 1 +1)>> 1 + 1 = 0
因为优先级的问题,一直出错
其实这个问题我之前遇见过,后来忘记了,所以 记录一下
当然 这道题使用双指针+排序效率是最高的
二分法例题: