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.
這道題是一道蠻有意思的題目,首先我們看題目中的例子,不管是houses還是heaters數組都是有序的,所以我們也需要給輸入的這兩個數組先排序,以免其為亂序。我們就拿第二個例子來分析,我們的目標是houses中的每一個數字都要被cover到,那么我們就遍歷houses數組,對每一個數組的數字,我們在heaters中找能包含這個數字的左右范圍,然后看離左右兩邊誰近取誰的值,如果某個house位置比heaters中最小的數字還小,那么肯定要用最小的heater去cover,反之如果比最大的數字還大,就用最大的數字去cover。對於每個數字算出的半徑,我們要取其中最大的值。通過上面的分析,我們就不難寫出代碼了,我們在heater中兩個數一組進行檢查,如果后面一個數和當前house位置差的絕對值小於等於前面一個數和當前house位置差的絕對值,那么我們繼續遍歷下一個位置的數。跳出循環的條件是遍歷到heater中最后一個數,或者上面的小於等於不成立,此時heater中的值和當前house位置的差的絕對值就是能cover當前house的最小半徑,我們更新結果res即可,參見代碼如下:
解法一:
class Solution { public: int findRadius(vector<int>& houses, vector<int>& heaters) { int n = heaters.size(), j = 0, res = 0; sort(houses.begin(), houses.end()); sort(heaters.begin(), heaters.end()); for (int i = 0; i < houses.size(); ++i) { int cur = houses[i]; while (j < n - 1 && abs(heaters[j + 1] - cur) <= abs(heaters[j] - cur)) { ++j; } res = max(res, abs(heaters[j] - cur)); } return res; } };
還是上面的思路,我們可以用二分查找法來快速找到第一個大於等於當前house位置的數,如果這個數存在,那么我們可以算出其和house的差值,並且如果這個數不是heater的首數字,我們可以算出house和前面一個數的差值,這兩個數中取較小的為cover當前house的最小半徑,然后我們每次更新結果res即可,參見代碼如下:
解法二:
class Solution { public: int findRadius(vector<int>& houses, vector<int>& heaters) { int res = 0, n = heaters.size(); sort(heaters.begin(), heaters.end()); for (int house : houses) { int left = 0, right = n; while (left < right) { int mid = left + (right - left) / 2; if (heaters[mid] < house) left = mid + 1; else right = mid; } int dist1 = (right == n) ? INT_MAX : heaters[right] - house; int dist2 = (right == 0) ? INT_MAX : house - heaters[right - 1]; res = max(res, min(dist1, dist2)); } return res; } };
我們可以用STL中的lower_bound來代替二分查找的代碼來快速找到第一個大於等於目標值的位置,其余部分均和上面方法相同,參見代碼如下:
解法三:
class Solution { public: int findRadius(vector<int>& houses, vector<int>& heaters) { int res = 0; sort(heaters.begin(), heaters.end()); for (int house : houses) { auto pos = lower_bound(heaters.begin(), heaters.end(), house); int dist1 = (pos == heaters.end()) ? INT_MAX : *pos - house; int dist2 = (pos == heaters.begin()) ? INT_MAX : house - *(--pos); res = max(res, min(dist1, dist2)); } return res; } };
參考資料:
https://discuss.leetcode.com/topic/71450/simple-java-solution-with-2-pointers
https://discuss.leetcode.com/topic/71460/short-and-clean-java-binary-search-solution/2
https://discuss.leetcode.com/topic/71440/c-solution-using-lower_bound-binary-search-with-comments