你有 k 个升序排列的整数数组。找到一个最小区间,使得 k 个列表中的每个列表至少有一个数包含在其中。

我们定义如果 b-a < d-c 或者在 b-a == d-c 时 a < c,则区间 [a,b] 比 [c,d] 小。

示例 1:

输入:[[4,10,15,24,26], [0,9,12,20], [5,18,22,30]]
输出: [20,24]

**解释: **

列表 1:[4, 10, 15, 24, 26],24 在区间 [20,24] 中。
列表 2:[0, 9, 12, 20],20 在区间 [20,24] 中。
列表 3:[5, 18, 22, 30],22 在区间 [20,24] 中。

注意:

  1. 给定的列表可能包含重复元素,所以在这里升序表示 >= 。
  2. 1 <= k <= 3500
  3. -105 <= 元素的值 <= 105

给定 k 个列表,需要找到最小区间,使得每个列表都至少有一个数在该区间中。该问题可以转化为,从 k 个列表中各取一个数,使得这 k 个数中的最大值与最小值的差最小。

假设这 k 个数中的最小值是第 i 个列表中的 x,对于任意 j != i,设第 j 个列表中被选为 k 个数之一的数是 y,则为了找到最小区间,y 应该取第 j 个列表中大于等于 x 的最小的数。

简单证明如下:假设 z 也是第 j 个列表中的数,且 z>y,则有 z-x>y-x,同时包含 x 和 z 的区间一定不会小于同时包含 x 和 y 的区间。因此,其余 k−1 个列表中应该取大于等于 x 的最小的数。

由于 k 个列表都是升序排列的,因此对每个列表维护一个指针,通过指针得到列表中的元素,指针右移之后指向的元素一定大于或等于之前的元素。

使用最小堆维护 k 个指针指向的元素中的最小值,同时维护堆中元素的最大值。初始时,k 个指针都指向下标 0,最大元素即为所有列表的下标 0 位置的元素中的最大值。

每次从堆中取出最小值,根据最大值和最小值计算当前区间,如果当前区间小于最小区间则用当前区间更新最小区间,然后将对应列表的指针右移,将新元素加入堆中,并更新堆中元素的最大值。

如果一个列表的指针超出该列表的下标范围,则说明该列表中的所有元素都被遍历过,堆中不会再有该列表中的元素,因此退出循环。

Code

 def smallestRange(self, nums: List[List[int]]) -> List[int]:rangeLeft, rangeRight = -10 ** 9, 10 ** 9# 初始时,k 个指针都指向下标 0,最大元素即为所有列表的下标 0 位置的元素中的最大值maxValue = max(vec[0] for vec in nums)priorityQueue = [(vec[0], i, 0) for i, vec in enumerate(nums)]heapq.heapify(priorityQueue)while True:minValue, row, idx = heapq.heappop(priorityQueue)if maxValue - minValue < rangeRight - rangeLeft:rangeLeft, rangeRight = minValue, maxValueif idx == len(nums[row]) - 1:breakmaxValue = max(maxValue, nums[row][idx + 1])heapq.heappush(priorityQueue, (nums[row][idx + 1], row, idx + 1))return [rangeLeft, rangeRight]

复杂度分析

时间复杂度:O(nklogk),其中 n 是所有列表的平均长度,k 是列表数量。所有的指针移动的总次数最多是 nk 次,每次从堆中取出元素和添加元素都需要更新堆,时间复杂度是 O(logk),因此总时间复杂度是 O(nklogk)。

空间复杂度:O(k),其中 k 是列表数量。空间复杂度取决于堆的大小,堆中维护 k 个元素。

632. Smallest Range Covering Elements from K Lists 最小区间相关推荐

  1. 77. Leetcode 1439. 有序矩阵中的第 k 个最小数组和 (堆-技巧二-多路归并)

    技巧二 - 多路归并其实这个技巧,叫做多指针优化可能会更合适,只不过这个名字实在太过朴素且容易和双指 针什么的混淆,因此我给 ta 起了个别致的名字 - 多路归并.多路体现在:有多条候选路线.代码上, ...

  2. 二叉搜索树中第k大元素_二叉搜索树中第K个最小元素

    二叉搜索树中第k大元素 Problem statement: 问题陈述: Find the k-th smallest element in a given binary search tree (B ...

  3. 【刷题】LOJ 6014 「网络流 24 题」最长 k 可重区间集

    题目描述 给定实直线 \(L\) 上 \(n\) 个开区间组成的集合 \(I\) ,和一个正整数 \(k\) ,试设计一个算法,从开区间集合 \(I\) 中选取出开区间集合 \(S \subseteq ...

  4. 选择问题(求第k个最小元素)

    什么是选择问题 划分的思路 Lomuto 划分 利用划分求第k小元素 C语言实现 改进 参考资料 什么是选择问题 选择问题(selection problem)是求一个n个数列表的第k个最小元素的问题 ...

  5. C语言在二叉搜索树找到第k个最小元素(附完整源码)

    C语言在二叉搜索树找到第k个最小元素 C语言在二叉搜索树找到第k个最小元素完整源码(定义,实现,main函数测试) C语言在二叉搜索树找到第k个最小元素完整源码(定义,实现,main函数测试) #in ...

  6. P3358 最长k可重区间集问题(网络流:串联思想)

    P3358 最长k可重区间集问题 这是一个经典模型,给定n个开区间,选择一些区间使得每个位置被覆盖次数不超过k,并最大化选择的区间长度之和. 首先一个直接的想法就是每一个区间匹配了它所对应的点,但是我 ...

  7. 786. 第 K 个最小的素数分数

    786. 第 K 个最小的素数分数 给你一个按递增顺序排序的数组 arr 和一个整数 k .数组 arr 由 1 和若干 素数  组成,且其中所有整数互不相同. 对于每对满足 0 < i < ...

  8. [Leetcode][第632题][JAVA][最小区间][堆][滑动窗口]

    [问题描述][困难] [解答思路] 1. 堆 复杂度 class Solution {public int[] smallestRange(List<List<Integer>> ...

  9. LeetCode 632. 最小区间(排序+滑动窗口)

    文章目录 1. 题目 2. 解题 1. 题目 你有 k 个升序排列的整数数组. 找到一个最小区间,使得 k 个列表中的每个列表至少有一个数包含在其中. 我们定义如果 b-a < d-c 或者在 ...

最新文章

  1. 写给程序员的最好的13条建议
  2. 全球与中国立式胶体磨市场发展现状调研及前景需求分析报告2022-2027年版
  3. Egret的容器--删除对象,遮罩
  4. [Visual Studio] 未能完成操作 不支持此接口
  5. java signed_如何从java中的字节读取signed int?
  6. 你的数仓函数结果不稳定,可能是属性指定错了
  7. python 逐行读取文件_Python fileinput模块:逐行读取多个文件
  8. 余承东宣布鸿蒙系统视频,余承东宣布鸿蒙系统开源:打造全球的操作系统
  9. 清除windows的EFS加密
  10. markdown首行空两格
  11. 怎么把小写字母(英文)转换成大写
  12. java可以进行爬虫吗_java能写爬虫程序吗
  13. allergo 命令
  14. Centos7 配置IP地址(动态或者静态)
  15. Python OpenCV 图像缩放 cv2.resize 方法
  16. STM32CubeMX的使用教程
  17. 「全网最细」:MRP1视图所有字段详解及实战应用 - 合集
  18. 支付宝-蚂蚁金服一面
  19. Ubantu错误汇总
  20. 使用u盘时要与计算机usb接口相连,u盘是通过什么接口与电脑交换数据的?

热门文章

  1. 快速解读linq语法
  2. Spring MVC请求处理流程
  3. unittest框架学习笔记
  4. BZOJ1146[CTSC2008]网络管理——出栈入栈序+树状数组套主席树
  5. [Coderforces600E] Lomsat gelral
  6. 坑爹的属性,android:descendantFocusability用法简析
  7. winrar 无法设置 xxx.aspx 的安全数据 -- 用批处理压缩文件在user账号下解压缩发生的错误...
  8. linux 搭建github,github在linux上的环境搭建-Go语言中文社区
  9. C语言学习之通过指针变量调用它所指向的函数
  10. python服务器查看文件更改记录,Python记录到同一文件,不同用户