• 【LeetCode】最小区间 [H](贪心)


    632. 最小区间 - 力扣(LeetCode)

    一、题目

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

    示例 1:
    输入:nums = [[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] 中。

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

    提示:

    • nums.length == k
    • 1 <= k <= 3500
    • 1 <= nums[i].length <= 50
    • -105 <= nums[i][j] <= 105
    • nums[i] 按非递减顺序排列

    二、代码

    1. class Solution {
    2. class Node {
    3. // 值大小
    4. public int value;
    5. // 该数来自哪个数组,记录数组编号
    6. public int arrid;
    7. // 该数来自数组的哪个下标位置
    8. public int index;
    9. public Node(int value, int arrid, int index) {
    10. this.value = value;
    11. this.arrid = arrid;
    12. this.index = index;
    13. }
    14. }
    15. // 有序表按照值得递增顺序排序,如果两个值相等,谁的数组编号小,谁就放在前面
    16. class NodeComparator implements Comparator {
    17. @Override
    18. public int compare(Node o1, Node o2) {
    19. return o1.value != o2.value ? o1.value - o2.value : o1.arrid - o2.arrid;
    20. }
    21. }
    22. public int[] smallestRange(List> nums) {
    23. // 创建有序表
    24. TreeSet ansSet = new TreeSet<>(new NodeComparator());
    25. // 一开始先将所有数组的第一个数加入到有序表中
    26. for (int i = 0; i < nums.size(); i++) {
    27. ansSet.add(new Node(nums.get(i).get(0), i, 0));
    28. }
    29. // 记录有序表最小的节点和最大的节点
    30. Node start = ansSet.first();
    31. Node end = ansSet.last();
    32. // 记录当前找到的符合条件的区间最窄的区间左右边界
    33. int min = start.value;
    34. int max = end.value;
    35. // 当我们想要删掉一个数据时,发现这个数据所在的数组已经没有别的数可以用来补充到有序表了,那么整个流程就不用再继续了,以为后面就无法满足每一个数组至少有一个数在有序表了
    36. while (start.index != nums.get(start.arrid).size() - 1) {
    37. // 弹出有序表中最小的数
    38. ansSet.pollFirst();
    39. // 将弹出的数所在数组的下一个位置的数加入到有序表中,保证这个数组有一个数在有序表中
    40. ansSet.add(new Node(nums.get(start.arrid).get(start.index + 1), start.arrid, start.index + 1));
    41. // 记录此时有序表的区间范围
    42. start = ansSet.first();
    43. end = ansSet.last();
    44. // 如果此时的区间比之前记录的更窄,就更新答案
    45. if (end.value - start.value < max - min) {
    46. max = end.value;
    47. min = start.value;
    48. // 如果此时的区间等于之前记录的区间,就看是否当前的区间起始数是不是比以前的起始数小,如果小就更新答案
    49. } else if (end.value - start.value == max - min) {
    50. if (start.value < min) {
    51. max = end.value;
    52. min = start.value;
    53. }
    54. }
    55. }
    56. // 返回符合条件的最窄区间
    57. return new int[] {min, max};
    58. }
    59. }

    三、解题思路 

    有序表能非常方便地查到所有数字最小值,也可以非常方便的查到所有数字的最大值。

    将每个数组中的第一个数加入有序表,取出最大值和最小值,可以找到一个区间。

    这个区间一定每个数组都有一个数落在这个区间上,

    然后删除最小值,把这个最小值来自数组的下一个值加入有序表,排序后重新取出最小值跟最大值,

    构成一个新的区间,跟之前的区间比较是否更优。

    当我们想要删掉一个数据时,发现这个数据所在的数组已经没有别的数可以用来补充到有序表了,那么整个流程就不用再继续了,这时就找到符合要求的最窄区间了。整个流程中我们可以保证在有序表的范围中每一个数据集合都至少有一个数在这个有序表所在的范围中。

    所以整个流程就相当于每一个数产生答案的时候都是某一个数字如果作为连续区间的开头往右怎么样最经济,

    这样你就把所有答案都穷举了一遍,然后从其中找最优解。而且整个流程一定就可以保证每一个数组只会有一个数在有序表中,可以尽最大可能保证区间范围最窄。

  • 相关阅读:
    五、vue组件与props自定义属性
    SQL 注入复习总结
    想要精通算法和SQL的成长之路 - 课程表II
    【动手学深度学习-Pytorch版】门控循环单元GRU
    rust学习(tokio协程分析一)
    感知器算法
    Python在不同场景下的并发编程方案选择
    史上最强 Java 学习路线图!
    4位密码锁可修改密码及错误报警VHDL
    C# 上位机Modbus Crc校验方法
  • 原文地址:https://blog.csdn.net/cy973071263/article/details/127949641