zoukankan      html  css  js  c++  java
  • [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 题目总结

  • 相关阅读:
    Leetcode 191.位1的个数 By Python
    反向传播的推导
    Leetcode 268.缺失数字 By Python
    Leetcode 326.3的幂 By Python
    Leetcode 28.实现strStr() By Python
    Leetcode 7.反转整数 By Python
    Leetcode 125.验证回文串 By Python
    Leetcode 1.两数之和 By Python
    Hdoj 1008.Elevator 题解
    TZOJ 车辆拥挤相互往里走
  • 原文地址:https://www.cnblogs.com/cnoodle/p/13413143.html
Copyright © 2011-2022 走看看