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