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

  • 相关阅读:
    [python2] python 打印表格 prettytable
    多条件查询
    excel模板导出一个新的文件
    通过反射的形式把集合的数据打印到log里
    C#写入log文本
    EF删除所有数据行的方法.所以下面给大家介绍几种方法.
    一种批量导出的方式
    一种简单的导出导入希望大神别介意
    excel导出
    excel的模板
  • 原文地址:https://www.cnblogs.com/sbj123456789/p/12178834.html
Copyright © 2011-2022 走看看