This is a two pointers problem.
First, we can easily prove the following facts:
If we were maintaining a set, which contains k numbers, each belongs to an independent row. Then selecting the smallest and biggest number in the set as the boundaries and this would be a valid range obviously. So now we just need to search all the sets and find the smallest range. This set can be maintained with two pointers.
Initially, creates
max
variable, indicates the max value of the heaprange
variable, indicates the current optimal answer’s range size, INF initiallyIn a loop,
top
, and calculates the max
minus top
range
top
if it has a next, otherwise break the loopThen we would get the optimal answer.
public class Solution {
public int[] smallestRange(List<List<Integer>> nums) {
List<Node> rows = nums.stream().map(row -> {
Iterator<Integer> it = row.iterator();
Node start = new Node(it.next());
Node node = start;
while (it.hasNext()) {
Node next = new Node(it.next());
node.next = next;
node = next;
}
return start;
}).collect(Collectors.toList());
PriorityQueue<Node> heap = new PriorityQueue<>(rows);
int[] ret = null;
int range = Integer.MAX_VALUE;
int max = rows.stream().mapToInt(raw -> raw.v).max().getAsInt();
while (true) {
Node top = heap.poll();
if (max - top.v < range) {
range = max - top.v;
ret = new int[]{top.v, max};
}
if (top.next != null) {
max = Math.max(max, top.next.v);
heap.add(top.next);
} else {
break;
}
}
return ret;
}
private static class Node implements Comparable<Node> {
int v;
Node next;
Node(int v) {
this.v = v;
}
@Override
public int compareTo(Node o) {
return v - o.v;
}
}
}