跳过正文
  1. leetcode 题解/

632_最小区间

·139 字·1 分钟

类型:字符串

    1. 最小区间 ❤️ ⭐

    https://leetcode-cn.com/problems/smallest-range-covering-elements-from-k-lists/

    ❓ 你有 k 个 非递减排列 的整数列表。找到一个 最小 区间,使得 k 个列表中的每个列表至少有一个数包含在其中。我们定义如果 b-a < d-c 或者在 b-a == d-c 时 a < c,则区间 [a,b] 比 [c,d] 小。

    💡 贪心 + 堆

    参见:力扣加加

    该问题可以转化为,从 k 个列表中各取一个数,使得这 k 个数中的最大值与最小值的差(diff)最小。

    思路是我们使用多指针进行遍历,将指向的元素存入小顶堆。通过堆顶获取最小值,通过一个变量来记录最大值,这样我们可以很快地计算出 diff。每次更新指针都会产生一个新的 diff,不断重复这个过程并维护全局最小 diff 即可。

    我们有这么多个指针,应该先移动哪一个呢?应该移动指向元素最小的指针(即堆顶),这样保证最小的元素被移出堆,才能保证 diff 的变化是渐进性的,才不会漏掉。

    class Solution:
        def smallestRange(self, martrix: List[List[int]]) -> List[int]:
            l, r = -10**9, 10**9
            # 将每一行最小的都放到堆中,同时记录其所在的行号和列号,一共 n 个齐头并进
            h = [(row[0], i, 0) for i, row in enumerate(martrix)]
            heapq.heapify(h)
            # 维护最大值
            max_v = max(row[0] for row in martrix)
    
            while True:
                min_v, row, col = heapq.heappop(h)
                # max_v - min_v 是当前的最大最小差值, r - l 为全局的最大最小差值。因为如果当前的更小,我们就更新全局结果
                if max_v - min_v < r - l:
                    l, r = min_v, max_v
                if col == len(martrix[row]) - 1: return [l, r]
                # 更新指针,继续往后移动一位
                heapq.heappush(h, (martrix[row][col + 1], row, col + 1))
                max_v = max(max_v, martrix[row][col + 1])