你有 k 个升序排列的整数数组。找到一个最小区间,使得 k 个列表中的每个列表至少有一个数包含在其中。
我们定义如果 b-a < d-c 或者在 b-a == d-c 时 a < c,则区间 [a,b] 比 [c,d] 小。
示例 1:
输入:[[4,10,15,24,26], [0,9,12,20], [5,18,22,30]]
输出: [20,24]
解释:
列表 1:[4, 10, 15, 24, 26],24 在区间 [20,24] 中。
列表 2:[0, 9, 12, 20],20 在区间 [20,24] 中。
列表 3:[5, 18, 22, 30],22 在区间 [20,24] 中。
思路:
/*
* 多个指针zero、first、second。。。同时从每个list的首元素出发。用pointerIndex来维护一个数组记录每个list当前指针的index。
比较三个指针对应的元素大小。记录比较后的curMin, curMax,更新smallest range。
移动curMin对应的指针,比较三个指针对应的元素大小。记录比较后的curMin, curMax,更新smallest range。 更新pointerIndex。
* PriorityQueue里面存放当前三个指针对应的元素。
PriorityQueue 删除极值的时间复杂度是 O(logN), 查找极值的时间复杂度是 O(1)
*/
public int[] smallestRange(List<List<Integer>> nums) {
int curMin = 0;
int curMax = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
int[] pointerIndex = new int[nums.size()];
boolean flag = true;
PriorityQueue<Integer> queue = new PriorityQueue<Integer>(
(i, j) -> nums.get(i).get(pointerIndex[i]) - nums.get(j).get(pointerIndex[j]));
for (int i = 0; i < nums.size(); i++) {
queue.add(i);
max = Math.max(max, nums.get(i).get(0));
}
for (int i = 0; i < nums.size() && flag; i++) {
for (int j = 0; j < nums.get(i).size() && flag; j++) {
int minValueLevel = queue.poll();
// 是否更新smallest range
if (max - nums.get(minValueLevel).get(pointerIndex[minValueLevel]) < curMax - curMin) {
curMin = nums.get(minValueLevel).get(pointerIndex[minValueLevel]);
curMax = max;
}
// 移动当前找到的最小值对应的pointer
pointerIndex[minValueLevel]++;
// flag辅助判断是否有某个list走到了末尾
if (pointerIndex[minValueLevel] == nums.get(minValueLevel).size()) {
flag = false;
break;
}
queue.offer(minValueLevel);
max = Math.max(max, nums.get(minValueLevel).get(pointerIndex[minValueLevel]));
}
}
return new int[] { curMin, curMax };
}
2.使用小顶堆和大顶堆
public int[] smallestRange(List<List<Integer>> nums) {
PriorityQueue<int[]> min=new PriorityQueue<>(1,new Comparator<int[]>(){
public int compare(int[] n1,int[] n2){
return nums.get(n1[0]).get(n1[1])-nums.get(n2[0]).get(n2[1]);
}
});
PriorityQueue<int[]> max=new PriorityQueue<>(1,new Comparator<int[]>(){
public int compare(int[] n1,int[] n2){
return nums.get(n2[0]).get(n2[1])-nums.get(n1[0]).get(n1[1]);
}
});
for(int i=0;i<nums.size();i++){
int[] tmp=new int[]{i,0};
min.offer(tmp);
max.offer(tmp);
}
int[] res=new int[]{Integer.MIN_VALUE,Integer.MAX_VALUE};
while(min.size()==nums.size()){
int[] m1=max.peek();
int[] m2=min.poll();
if((long)nums.get(m1[0]).get(m1[1])-(long)nums.get(m2[0]).get(m2[1])<(long)res[1]-(long)res[0]){
res[0]=nums.get(m2[0]).get(m2[1]);
res[1]=nums.get(m1[0]).get(m1[1]);
}
if(m2[1]+1<nums.get(m2[0]).size()){
int[] m3=new int[]{m2[0],m2[1]+1};
min.offer(m3);
max.offer(m3);
max.remove(m2);
}
}
return res;
}