You have k
lists of sorted integers in ascending order. Find the smallest range that includes at least one number from each of thek
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<List<Integer>>. And after you reset the code template, you'll see this point.
思路:遇到这题,我一开始就想 想出最优解,然后想到用Binary Search,毕竟是满足一定条件下求最值问题,但是后面一直WA,主要是因为是求范围,有2个变量在变
后面看Discuss里面先尝试用Brute force然后慢慢优化到最优解,发现想不出来还是得一步步慢慢来
Brute force 就是枚举了,每个数组都取出一个数,然后用一个范围包括这些数。主要在枚举过程中记录最小的range就OK了
想到这里应该可以联想到用优先队列来减小这个枚举过程的重复计算量,其具体过程类似于merge K个数组一样
package l632;
import java.util.Comparator;
import java.util.List;
import java.util.PriorityQueue;
/*
* 先往Brute force想,就是遍历每个数组拿出一个
* 肯定重复计算很多,所以然后再考虑优化
*
* 从每个数组中取出一个放到一个最小堆,用一个范围包括这些数字不就是一个合理的range了
* 每次就从抽出来的数中拿出最小的那个数,然后再加入在那个数组里面后面的那个数
* 当加不了时就结束了,在这个过程中收集range最小的答案
*/
public class Solution {
public int[] smallestRange(List<List<Integer>> nums) {
PriorityQueue<int[]> minHeap = new PriorityQueue<int[]>(nums.size(), new Comparator<int[]>(){
public int compare(int[] o1, int[] o2) {
return o1[0] - o2[0];
}
});
int max = nums.get(0).get(0);
for(int i=0; i<nums.size(); i++) {
minHeap.add(new int[]{nums.get(i).get(0), i, 0});
max = Math.max(max, nums.get(i).get(0));
}
int minRange = Integer.MAX_VALUE;
int start = -1;
while(minHeap.size() == nums.size()) {
int[] t = minHeap.poll();
if(max - t[0] < minRange) {
minRange = max - t[0];
start = t[0];
}
if(t[2]+1 < nums.get(t[1]).size()) {
t[0] = nums.get(t[1]).get(t[2]+1);
t[2] ++;
minHeap.add(t);
max = Math.max(max, t[0]);
}
}
return new int[]{start, start+minRange};
}
}