题目
你有 k 个升序排列的整数数组。找到一个最小区间,使得 k 个列表中的每个列表至少有一个数包含在其中。
我们定义如果 b-a < d-c 或者在 b-a == d-c 时 a < c,则区间 [a,b] 比 [c,d] 小。
题解
大纲思路如下:
1、定义一个当前最优解的数组 R,格式为 [x, y] ;
2、定义一个迭代数列 D,长度为k,格式为 [ x1, x2, x3, …, xk ] ;
3、首先,取出每一个数组中最小的数放入迭代数列 D 中,计算当前最优解的值 R ;
4、之后,选择迭代数组中最小的那个,将其替换为其对应数组中的下一个数,再对迭代数列 D 进行最优解计算,将计算结果与 R 进行比较,若优于 R 则替换 R ,否则跳过,继续进行该步骤,直至每一个数列都取到了最后一个数为之。
具体函数设计:
1、数据基础设定
数据名称 | 数据类型 | 数据用途 |
---|---|---|
R | int[] | 最优解数组 |
D | int[] | 迭代数组 |
index | int[] | 当前迭代位置下表数组 |
nums | List<List<Intager>> | k个升序排列的有序数组 |
2、辅助函数设计
ArrayFull()
输入:nums、index
输出:boolean
功能:判断当前循环是否到达数组最后一位,仅全部的 index[i] = nums[i].size() 时返回 false ,否则返回 true 。
ArrayBest()
输入:D
输出:R#
功能:计算当前迭代数组的最优解,并返回当前数组最优解
ArraySmallest()
输入:D
输出:s
功能:找出最小的数的下标的下一位
RightIndex()
输入:D、index、nums
输出:k
功能:修正ArraySmallest()函数寻找的下标,保证其下标不是该数组的最后一位
CompareR()
输入:R、Ri
输出:R
功能:比较R与Ri谁更小
3、主函数设计
初始化数据
当ArrayFull()函数为true时,执行以下循环:
寻找最小数下标
更新index,指定下标的index+1
更新迭代数组D
更新最终结果R
程序
待修改的代码:
public class SmallestRange {
public int[] smallestRange(List<List<Integer>> nums) {
int[] R = new int[2]; //当前最优解
List<Integer> D = new ArrayList<Integer>(nums.size()); //迭代数组
List<Integer> index = new ArrayList<Integer>(nums.size()); //迭代指针
int smallest_index;
for(int i = 0; i < nums.size(); i++) { //初始化迭代数组
D.add(nums.get(i).get(0));
}
R = this.ArrayBest(D); //初始化最优解数组
for(int i = 0; i < nums.size(); i++) { //初始化迭代下标
index.add(0);
}
while( this.ArrayFull(nums, index) ) {
/*
* 寻找最小数下标
* 更新index,指定下标的index+1
* 更新迭代数组D
*/
smallest_index = this.RightIndex(D, index, nums);
index.set(smallest_index, index.get(smallest_index)+1);
D.set(smallest_index, nums.get(smallest_index).get(index.get(smallest_index)));
R = this.ArrayBest(D);
}
return R;
}
public boolean ArrayFull(List<List<Integer>> nums, List<Integer> index) {
// 判断index是否均为最后一位
for(int i = 0; i < index.size(); i++) {
if(index.get(i) == nums.get(i).size() - 1) {
continue;
}else {
return true;
}
}
return false;
}
public int[] ArrayBest(List<Integer> D) {
// 计算当前迭代数组的最优解,并返回当前数组最优解
int[] Ri = new int[2];
if(D.get(0) < D.get(1)) {
Ri[0] = D.get(0);
Ri[1] = D.get(1);
}else {
Ri[0] = D.get(1);
Ri[1] = D.get(0);
}
for(int i = 2; i < D.size(); i++) {
if(D.get(i) > Ri[1]) {
Ri[1] = D.get(i);
}else if(D.get(i) < Ri[0]) {
Ri[0] = D.get(i);
}
}
return Ri;
}
public int ArraySmallest(List<Integer> D) {
// 寻找数组D中最小的数的下标
int z = D.get(0);
int k = 0;
for(int i = 1; i < D.size(); i++) {
if(D.get(i) < z) {
z = D.get(i);
k = i;
}
}
return k;
}
public int RightIndex(List<Integer> D, List<Integer> index, List<List<Integer>> nums) {
// 修正下标,确保下表不是最后一位
int k = this.ArraySmallest(D);
List<Integer> D_cut = new ArrayList<Integer>();
for(int i = 0; i < D.size(); i++) {
D_cut.add(index.get(i));
}
while( index.get(k) == nums.get(k).size()-1 ) {
D_cut.remove(k);
k = this.ArraySmallest(D_cut);
}
return k;
}
public int[] CompareR(int[] R, int[] Ri) {
if(R[1] - R[0] > Ri[1] - Ri[0]) {
return Ri;
}else if(R[1] - R[0] < Ri[1] - Ri[0]){
return R;
}else if(R[1] - R[0] == Ri[1] - Ri[0]){
if(R[0] > Ri[0]) {
return Ri;
}else {
return R;
}
}
return R;
}
//测试主函数
public static void main(String[] args) {
SmallestRange s = new SmallestRange();
List<List<Integer>> L = new ArrayList<List<Integer>>();
Integer[][] k = {{4,10,15,24,26}, {0,9,12,20}, {5,18,22,30}};
for(int i = 0; i < k.length; i++ ) {
L.add((List<Integer>)Arrays.asList(k[i]));
}
//int[] R = s.smallestRange(L);
//System.out.println(R);
int[] R = {20, 24};
int[] Ri = {20, 26};
System.out.println(s.CompareR(R, Ri)[0] + s.CompareR(R, Ri)[1]);
}
}