在问 · 算法题解

475. 供暖器

中等二分查找排序 + 二分查找力扣原题 ↗

题目描述

房屋和供暖器都位于同一条数轴上,houses 给出各房屋的位置,heaters 给出各供暖器的位置。

所有供暖器共用同一个加热半径 r:位于 x 的供暖器能让 [x - r, x + r] 内的房屋取暖。

返回能让每间房屋至少被一个供暖器覆盖的最小 r。

示例 1
输入:houses = [1,2,3], heaters = [2]
输出:1

解释:唯一的供暖器在 2,半径 1 可覆盖 1 到 3。

示例 2
输入:houses = [1,2,3,4], heaters = [1,4]
输出:1

解释:供暖器在 1 和 4,半径 1 时 2 由前者覆盖、3 由后者覆盖。

示例 3
输入:houses = [1,5], heaters = [2]
输出:3

解释:房屋 5 距离唯一的供暖器 2 有 3 远,半径至少为 3。

数据范围

  • 1 <= houses.length, heaters.length <= 3 * 10^4
  • 1 <= houses[i], heaters[i] <= 10^9

解题思路:排序 + 二分查找

每间房屋只需要离它最近的供暖器。把 heaters 排序,对房屋 h 用 bisect_left 找第一个 >= h 的供暖器 heaters[j],最近的只可能是它或它左边的 heaters[j-1]。取两者距离较小值,就是这间房屋需要的半径;答案是所有房屋需要半径的最大值。

为什么正确

ans 是已处理房屋各自到最近供暖器距离的最大值。

复杂度分析

排序 O(m log m),每间房屋二分 O(log m),总时间 O((n + m) log m),额外空间 O(1)(不计排序)。

易错点

j 可能等于 0 或 len(heaters),这时只有一侧有供暖器,要先判断边界再取值。houses 不需要排序,但 heaters 必须排序。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def findRadius(self, houses: List[int], heaters: List[int]) -> int:
        heaters.sort()
        ans = 0
        for h in houses:
            j = bisect_left(heaters, h)
            d = float('inf')
            if j < len(heaters):
                d = heaters[j] - h
            if j > 0:
                d = min(d, h - heaters[j - 1])
            ans = max(ans, d)
        return ans

载入编辑器,自己跑一遍 →

其他解法

二分只需对供暖器排序,每个房屋独立查找;双指针利用两个有序数组的单调性,用一次合并式扫描代替多次二分。

解法 2:排序 + 双指针 时间 O(n log n + m log m),空间 O(log n + log m)

把房屋和供暖器都排序。按顺序处理房屋时,离它最近的供暖器下标只会向右移动:只要下一个供暖器距离不比当前的远,就把指针右移。每个房屋取到最近供暖器的距离,所有房屋取最大值即为答案。

扫描部分是线性的,不需要二分。但房屋数组也要排序,并且要想清楚指针单调移动的条件(相等时也要右移)。

class Solution:
    def findRadius(self, houses: List[int], heaters: List[int]) -> int:
        houses = sorted(houses)
        heaters = sorted(heaters)
        ans = j = 0
        for h in houses:
            # 房屋有序,最近的供暖器下标只会右移
            while j + 1 < len(heaters) and abs(heaters[j + 1] - h) <= abs(heaters[j] - h):
                j += 1
            ans = max(ans, abs(heaters[j] - h))
        return ans

二分查找 专题的其他题目

查看 二分查找 全部题目 →