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;
}
}