[LeetCode] 632. Smallest Range

Problem

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:
The given list may contain duplicates, so ascending order means >= here.
1 <= k <= 3500
-105 <= value of elements <= 105.
For Java users, please note that the input type has been changed to List>. And after you reset the code template, you'll see this point.

Solution #1 using one PriorityQueue to store position and sort by value

class Solution {
    public int[] smallestRange(List> nums) {
        //queue is used to save positions  and sort by value
        PriorityQueue queue = new PriorityQueue<>(Comparator.comparingInt(o -> nums.get(o[0]).get(o[1])));
        //yes, update two pointers later
        int max = Integer.MIN_VALUE, start = 0, end = Integer.MAX_VALUE;
        for (int i = 0; i < nums.size(); i++) {
            //put the first element in each row to the queue
            queue.offer(new int[]{i, 0});
            //max is the maximum of the first num in all rows
            max = Math.max(max, nums.get(i).get(0));
        }
        while (queue.size() == nums.size()) {
            //after you polled the smallest: 
            //update two pointers;  offer the next one in that row;  update max
            int[] a = queue.poll();
            int row = a[0], col = a[1];
            if (end-start > max-nums.get(row).get(col)) {
                start = nums.get(row).get(col);
                end = max;
            }
            if (col+1 < nums.get(row).size()) {
                queue.offer(new int[]{row, col+1});
                max = Math.max(max, nums.get(row).get(col+1));
            }
        }
        return new int[]{start, end};
    }
}

Solution #2 Create a Ng (Number-Group) class... a good thought but not a good solution

class Solution {
    public int[] smallestRange(List> nums) {
        List list = new ArrayList<>();
        for (int g = 0; g < nums.size(); g++) {
            for (Integer i: nums.get(g)) {
                list.add(new Ng(i, g));
            }
        }
        Collections.sort(list, (a, b)->a.num-b.num);
        int start = 0, end = list.size();
        int count = 0;
        int l = 0, r = 0;
        int[] groups = new int[nums.size()];
        while (l < list.size()) {
            if (count < nums.size() && r < list.size()) {
                Ng cur = list.get(r);
                groups[cur.group]++;
                if (groups[cur.group] == 1) count++;
                r++;
            } else {
                Ng cur = list.get(l);
                groups[cur.group]--;
                if (groups[cur.group] == 0) count--;
                l++;
            }
            if (count == nums.size()) {
                if (list.get(r-1).num-list.get(l).num < list.get(end-1).num-list.get(start).num) {
                    start = l;
                    end = r;
                }
            }
        }
        
        return new int[]{list.get(start).num, list.get(end-1).num};
    }
}
class Ng {
    int num;
    int group;
    public Ng(int n, int g) {
        this.num = n;
        this.group = g;
    }
}

你可能感兴趣的:([LeetCode] 632. Smallest Range)