zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    html中label及加上属性for之后的用法
    Django中利用filter与simple_tag为前端自定义函数的实现方法
    关于自动编译iOS工程,生成app及ipa文件的方法-备
    ios打包ipa的四种实用方法(.app转.ipa)-备
    为GCD队列绑定NSObject类型上下文数据-利用__bridge_retained(transfer)转移内存管理权-备
    GCD使用经验与技巧浅谈--备
    h5与iOS的wkwebview不兼容问题
    cocoaPods 安装和应用
    .a静态库的注意事项
    UIApplication详解再解-备
  • 原文地址:https://www.cnblogs.com/sbj123456789/p/12178834.html
Copyright © 2011-2022 走看看