前言
紧密关联有序 + 找元素 + 二分,能够降低时间复杂度,甚至是解题。多练题,找到题感才能找到看问题的角度,对细节的处理也会更加得心应手,而不是死知识点,见招拆招的能力会更强。
一、供暖器
二、二分 || 双指针
1、二分寻找
// 供暖器
public class FindRadius {
/*
角度没对,角度没题感 + 角度较乱。
以前:两个空调之间的距离 / 2,错了。
题解:想要每个房间都被覆盖,且求最小覆盖,应该看每个房间离得最近的空调,然后记录值,对于所有房间,记录最大值即可。
idea:为了便于寻找空调,所以对空调位置排序,采用二分寻找。
*/
public int findRadius(int[] houses, int[] heaters) {
Arrays.sort(heaters);
int max = 0;
for (int h : houses) max = Math.max(max, binarySearch(heaters, h));
return max;
}
public int binarySearch(int[] heaters, int target) {
int low = 0, high = heaters.length;
while (low < high) {
int mid = low + (high - low >> 1);
int midVal = heaters[mid];
if (midVal > target) high = mid;
else low = mid + 1;
}
if (low == heaters.length) return target - heaters[low - 1];
if (low == 0) return heaters[0] - target;
return Math.min(Math.abs(target - heaters[low - 1]), Math.abs(target - heaters[low]));
}
}
2、双指针
// 一旦明确了题目要求和看题角度,那么可使用其他方法进行解答。
class FindRadius2 {
/*
角度没对,角度没题感 + 角度较乱。
以前:两个空调之间的距离 / 2,错了。
题解:想要每个房间都被覆盖,且求最小覆盖,应该看每个房间离得最近的空调,然后记录值,对于所有房间,记录最大值即可。
idea:可以对房子位置和空调位置都排序,同时遍历,求每个房子最近的供暖器。
*/
public int findRadius(int[] houses, int[] heaters) {
Arrays.sort(houses);
Arrays.sort(heaters);
int max = 0, idx = 0;
for (int h : houses) {
// bug1:有重复房间,要寻找最近的哪一个。
// bug2:最后一个空调了,就不能往下找了。
while (idx < heaters.length - 1 && heaters[idx] < h) ++idx;
int m = Math.abs(h - heaters[idx]);
int n = idx == 0 ? Integer.MAX_VALUE : h - heaters[idx - 1];
max = Math.max(max, Math.min(m, n));
}
return max;
}
}
总结
1)看问题角度正确,影响着是否能够解题,而题量产生的题感对看问题的角度也有很大的影响。
2)紧密关联有序 + 找元素 + 二分,相互联系,相互提醒。
3)题要多练,因为很多题不是刚好嵌入一个知识点,而是四邻八脚,就会体现出很多细节,需要有见招拆招的能力,才能解题。这应该是通常讲的debug部分吧,一些边界/重复等等辅助因素导致的错误。
参考文献
[1] LeetCode 供暖器