思路:
O(n^2)的方法很好想,但太慢了
朴素想法: 既然每个数组已经有序,找到m个数组第一个元素中的最小值,再找到每个数组最后一个元素的最大值就行了
问题: 题目要求两个元素不能来自于同一个数组,所以考虑记录次小和次大,即便最小和最大是来自同一个的,根据次优值算就行了。
最小min1, 次小min2, 最大max1, 次大max2
若min1, max1不是来自同一个数组,结果就是|min1-max1|
若是来自同一个数组,结果就是max(|min1, max2|, |min2, max1|)
解法1:
建两个优先队列,每个队列长度为2
遍历过程中还需要记录两个队列头元素是否来自同一个数组,用fromSame记录
首先将第一个数组的最小,最大分别入队,fromSame设置为true
遍历剩余数组:最小,最大分别入队,fromSame更新机制为:
fromSame=true仅有以下两种情况:
1.该数组同时出现了更小和更大的,即都来自当前遍历的数组
2.fromSame已经为true,且当前遍历的数组,既没有更小的,也没有更大的,fromSame依然为true
否则,fromSame置为false
class Solution {
public int maxDistance(List<List<Integer>> arrays) {
PriorityQueue<Integer> minQ=new PriorityQueue<>(2, (a,b)->a-b);
PriorityQueue<Integer> maxQ=new PriorityQueue<>(2, (a,b)->b-a);
List<Integer> tmp = arrays.get(0);
minQ.add(tmp.get(0));
maxQ.add(tmp.get(tmp.size()-1));
boolean fromSame=true;
for(int i=1;i<arrays.size();i++){
tmp=arrays.get(i);
int minEle = tmp.get(0);
int maxEle = tmp.get(tmp.size()-1);
if(minEle<minQ.peek() && maxEle>maxQ.peek()){
fromSame=true;
}else if(fromSame && minEle>minQ.peek() && maxEle<maxQ.peek()){
fromSame=true;
}else{
fromSame=false;
}
minQ.add(minEle);
maxQ.add(maxEle);
}
if(!fromSame){
return Math.abs(minQ.peek()-maxQ.peek());
}
int min1=minQ.poll();
int min2=minQ.poll();
int max1=maxQ.poll();
int max2=maxQ.poll();
return Math.max(
Math.abs(min1-max2),
Math.abs(min2-max1)
);
}
}
解法2:
直接开4个变量记录最大,最小,次大,次小,其余不变
省去队列插入的复杂度
class Solution {
public int maxDistance(List<List<Integer>> arrays) {
int min1,min2,max1,max2;
List<Integer> tmp = arrays.get(0);
min1=tmp.get(0);
max1=tmp.get(tmp.size()-1);
boolean fromSame=true;
for(int i=1;i<arrays.size();i++){
tmp=arrays.get(i);
int minEle = tmp.get(0);
int maxEle = tmp.get(tmp.size()-1);
//更新fromSame
if((minEle<min1 && maxEle>max1) || (fromSame && minEle>min1 && maxEle<max1)){
fromSame=true;
}else{
fromSame=false;
}
//更新最大最小值
if(minEle<=min1){
min2=min1;
min1=minEle;
}else if(minEle<=min2){
min2=minEle;
}
if(maxEle>=max1){
max2=max1;
max1=maxEle;
}else if(maxEle>=max2){
max2=maxEle;
}
}
if(!fromSame){
return Math.abs(max1-min1);
}
return Math.max(
Math.abs(min1-max2),
Math.abs(min2-max1)
);
}
}
解法3:
前两个都是在最后才确认最大和最小,所以需要记录次大,次小
实际上,可以遍历每个新数组时,更新最大,最小,抛开次大、次小