• 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 90. 子集 II dfs
    Leetcode 83. 删除排序链表中的重复元素 链表操作
    《算法竞赛进阶指南》 第二章 Acwing 139. 回文子串的最大长度
    LeetCode 80. 删除有序数组中的重复项 II 双指针
    LeetCode 86 分割链表
    《算法竞赛进阶指南》 第二章 Acwing 138. 兔子与兔子 哈希
    《算法竞赛进阶指南》 第二章 Acwing 137. 雪花雪花雪花 哈希
  • 原文地址:https://www.cnblogs.com/sbj123456789/p/12178834.html
Copyright © 2020-2023  润新知