LeetCode #475 Heaters

Posted sbj123456789

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode #475 Heaters相关的知识,希望对你有一定的参考价值。

Question

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:

  1. Numbers of houses and heaters you are given are non-negative and will not exceed 25000.
  2. Positions of houses and heaters you are given are non-negative and will not exceed 10^9.
  3. As long as a house is in the heaters\' warm radius range, it can be warmed.
  4. 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.

遍历

此题虽然是easy题,但想法上不是很直接,细节上也有很值得注意的地方。

首先如果按照题目的想法,想着遍历heaters去包含houses,然后取最大值,这么想就偏了。正确的想法是遍历houses去计算离其最近的heaters,每一个house可以对应一个radius,然后再对这些radius取max就行了。这个转换的思想很关键。

在找到最近的heaters中有几个很重要的细节。

1. 什么时候将heaters的index前移。由于是遍历houses,heaters的index是不可能通过遍历来移动的,只能通过houses的index,在达到一定条件后前移。

这里的答案是当 下一个heater到当前house的距离 小于等于 当前heater到当前house的距离,即 abs(heaters[j+1] - houses[i]) <= abs(heaters[j] - houses[i] 。

2. 为什么用while不是if。

给出反例:

[1, 1, 100, 100]

[49, 50, 51]

当要连续跳过多个heater的情况。

3. 为什么判断距离时是 <= 不是 <

给出反例

[1,2,3,4,5,5,6,7,8,9]
[1,2,3,4,5,5,6,7,8,9]

当 abs(heaters[j+1] - houses[i]) 和 abs(heaters[j] - houses[i] 相等时,heater的index无法前移

class Solution:
    def findRadius(self, houses: List[int], heaters: List[int]) -> int:
        houses.sort()
        heaters.sort()
        j = 0
        radius = 0
        heaters_num = len(heaters)
        for i in range(len(houses)):
            while j < heaters_num - 1 and abs(heaters[j+1] - houses[i]) <= abs(heaters[j] - houses[i]):
                j += 1
            radius = max(radius, abs(houses[i] - heaters[j]))
            print(j)
        return radius

遍历 - 改进

看了一下别人的代码,发现之前的方法太绕了,不够直接。

class Solution:
    def findRadius(self, houses: List[int], heaters: List[int]) -> int:
        houses.sort()
        heaters.sort()
        j = 0
        radius = 0
        heaters = [float(\'-inf\')] + heaters + [float(\'inf\')]
        for house in houses:
            while house > heaters[j]:
                j += 1
            min_dis = min(abs(heaters[j-1] - house), abs(heaters[j] - house))
            radius = max(radius, min_dis)
        return radius

其实只要判断house前后两个heater的距离就可以了,heater的移动通过当前house与当前heater的位置来判断。

这个方法要比之前的方法简单,bug少,好实现。可见选择一个简单的思路是很重要的(奥姆剃刀原理)。

二分查找

当不对houses进行排序时,可以用二分查找来找到第一个大于等于houses[i]的heater,然后就可以定位到前一个与后一个heater,从而进行比较。

手写版二分查找:

class Solution:
    def findRadius(self, houses: List[int], heaters: List[int]) -> int:
        heaters.sort()
        heaters = [float(\'-inf\')] + heaters + [float(\'inf\')]
        radius = 0
        for house in houses:
            left = 1
            right = len(heaters) - 2
            while left < right:
                mid = left + (right - left) // 2
                if heaters[mid] < house: left = mid + 1
                else: right = mid
            # print(left)
            min_dis = min(abs(heaters[left-1] - house), abs(heaters[left] - house))
            radius = max(radius, min_dis)
            # print(radius)
        return radius

还可以用bisect,即相当于C++中的lower_bound()

class Solution:
    def findRadius(self, houses: List[int], heaters: List[int]) -> int:
        import bisect
        heaters.sort()
        # heaters = [float(\'-inf\')] + heaters + [float(\'inf\')]
        heaters = [float(\'-inf\')] +  heaters
        radius = 0
        for house in houses:
            left = bisect.bisect(heaters, house, lo=1, hi=len(heaters)-1)
            min_dis = min(abs(heaters[left-1] - house), abs(heaters[left] - house))
            radius = max(radius, min_dis)
            # print(radius)
        return radius

bisect的使用可参考 https://www.cnblogs.com/sbj123456789/p/12186524.html

这里用bisect.bisect()和bisect.bisect_right()都可以,因为heaters[i]和house相等时都能找到正确解。

 

 

参考:

https://www.cnblogs.com/grandyang/p/6181626.html

https://leetcode.com/problems/heaters/discuss/95878/10-lines-python-with-easy-understanding

https://www.cnblogs.com/sbj123456789/p/12186524.html

以上是关于LeetCode #475 Heaters的主要内容,如果未能解决你的问题,请参考以下文章

leetcode 475. 供暖器(Heaters)

475. Heaters

leetcode每日一题(475.供暖器)

475.Heaters java

475. Heaters

475. Heaters (start binary search, appplication for binary search)