• [LeetCode] 632. Smallest Range Covering Elements from K Lists


    You have k lists of sorted integers in ascending order. Find the smallest range that includes at least one number from each of the k lists.

    We define the range [a,b] is smaller than range [c,d] if b-a < d-c or a < c if b-a == d-c.

    Example 1:

    Input: [[4,10,15,24,26], [0,9,12,20], [5,18,22,30]]
    Output: [20,24]
    Explanation: 
    List 1: [4, 10, 15, 24,26], 24 is in range [20,24].
    List 2: [0, 9, 12, 20], 20 is in range [20,24].
    List 3: [5, 18, 22, 30], 22 is in range [20,24].

    Note:

    1. The given list may contain duplicates, so ascending order means >= here.
    2. 1 <= k <= 3500
    3. -105 <= value of elements <= 105.

    最小区间。

    题意是给一个list of list,sublist里面都是整数,且每个sublist都是有序的。请返回一个最小区间,使得input里的每个sublist至少有一个元素在这个最小区间里。

    这道题我是用priority queue做的。大体的思路类似23. Merge k Sorted Lists。既然每个sub list自己都是非递减的,所以当我们从每个sub list拿出一个元素放入priority queue的时候,priority queue的size = sub list的个数。每当从priority queue弹出一个元素的时候,我们需要知道弹出的这个元素是从哪个sub list来的,并且要从对应的那个sub list补一个元素进来,这样priority queue里面的元素才会始终包含来自所有sub list的元素。

    我们照着这个例子讲一下思路,

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

    因为每个sublist都是有序的,所以可以先把每个sublist的第一个元素加入一个以priority queue创建的最小堆,这样,最小的元素始终在堆顶。在把所有sublist的第一个元素加入pq之后,同时也得到了一个第一个区间[0, 5]。

    接着开始往后遍历,因为第一个区间是[0, 5],如果想试着缩小这个区间,那么要不然就是提高下限要不然就是压低上限。因为所有的sublist都是递增的所以只能试着提高下限。因为0又是堆顶元素,所以去掉0,加入0所在的sublist之后的那个数字9。此时pq里是[4, 5, 9],同时最大元素是9,最小元素是4,新的区间是[4, 9],区间并没有比之前小,不更新。

    第三轮,此时因为堆顶元素是4,所以弹出4,加入4之后的那个元素10,此时pq里面是[5, 9, 10],新的区间是[5, 10],区间并没有比之前小,不更新。

    第四轮,堆顶元素是5,弹出5,加入5之后的那个元素18,此时pq里面是[9, 10, 18],区间并没有比之前小,不更新。

    第五轮,堆顶元素9,弹出9,加入9之后的那个元素12,此时pq里面是[10, 12, 18],区间并没有比之前小,不更新。

    第六轮,堆顶元素10,弹出10,加入10之后的那个元素15,此时pq里面是[12, 15, 18],区间并没有比之前小,不更新。

    ……

    照着这个方式去遍历,把所有sublist里面的数字都通过pq过滤一遍,最后会得到最小的区间[20, 24]。

    时间O(nlogk)

    空间O(k)

    Java实现

     1 class Solution {
     2     public int[] smallestRange(List<List<Integer>> nums) {
     3         // corner case
     4         if (nums == null || nums.size() == 0) {
     5             return new int[0];
     6         }
     7 
     8         // normal case
     9         PriorityQueue<int[]> queue = new PriorityQueue<>((a, b) -> a[0] - b[0]);
    10         int n = nums.size();
    11         int min = Integer.MAX_VALUE;
    12         int max = Integer.MIN_VALUE;
    13         int res = Integer.MAX_VALUE;
    14         for (int i = 0; i < n; i++) {
    15             // {sublist里面的元素, sublist的下标,这个元素在sublist里的index}
    16             queue.offer(new int[] { nums.get(i).get(0), i, 0 });
    17             min = Math.min(min, nums.get(i).get(0));
    18             max = Math.max(max, nums.get(i).get(0));
    19         }
    20 
    21         int start = min;
    22         int end = max;
    23 
    24         while (queue.size() == n) {
    25             int[] cur = queue.poll();
    26             int value = cur[0];
    27             int listIndex = cur[1];
    28             int subIndex = cur[2];
    29             if (subIndex + 1 < nums.get(listIndex).size()) {
    30                 queue.offer(new int[] { nums.get(listIndex).get(subIndex + 1), listIndex, subIndex + 1 });
    31                 max = Math.max(max, nums.get(listIndex).get(subIndex + 1));
    32                 min = queue.peek()[0];
    33                 if (max - min < end - start) {
    34                     end = max;
    35                     start = min;
    36                 }
    37             }
    38         }
    39         return new int[] { start, end };
    40     }
    41 }

    sliding window的思路日后有机会再补充。

    LeetCode 题目总结

  • 相关阅读:
    java提高篇(四)-----抽象类与接口
    hdu1004----用java链表实现
    jkfladsdjfkldsa
    Handler_1
    Handler实现线程间的通信2
    Handler实现线程间的通信1
    Handler基本运行机制
    Android线程
    Activity声明周期2
    Activity声明周期1
  • 原文地址:https://www.cnblogs.com/cnoodle/p/13413143.html
Copyright © 2020-2023  润新知