[程序源代码面试指南第二版] 生成窗口最大值数组 刷子刷题越刷越傻,过阵再回来重新笔记
需求
双端队列整型arr和w窗口从arr数组左到右,窗口每次滑动一个位置,比如
[4 3 5] 4 3 3 6 7
4 [3 5 4] 3 3 6 7
4 3 [5 4 3] 3 6 7
4 3 5 [4 3 3] 6 7
4 3 5 4 [3 3 6] 7
4 3 5 4 3 [3 6 7]
咳咳
例如,上述例子
- qmax = {}
[4 3 5] 4 3 3 6 7
- qmax为空直接把下标i放进qmax,qmax={0}
arr[0]==4,下标0放入qmax
- 如果qmax不为空,当前qmax队尾下标j,如果
arr[j]>arr[i],直接把下标i放入qmax,qmax={0,1}
arr[1]==3,当前qmax的队尾下标0,并且arr[0] > arr[1],所以将i值(这里为1)放入queue的尾部
- 如果qmax不为空,
arr[j]<=arr[i],把j从qmax中弹出,直到arr[j]>arr[i]或qmax空,qmax={2}
arr[2]==5,当前qmax的队尾下标为1,并且arr[1]<=arr[2],所以将下标1从queue尾部弹出,所以qmax变为{0}
当前qmax的队尾下标为0,并且arr[0]<=arr[2],所以将下标0从queue尾部弹出,所以qmax变为{};将下标2放入qmax,qmax={2}
- 如果队头下标=i-w,说明当前qmax队头下标过期,须弹出,qmax={2,3}
arr[3]==4,当前qmax队尾下标2,arr[2]>arr[3],所以将下标3放入qmax尾部,此时队头下标2还没有过期
窗口[1..3]最大值arr[2]
- qmax={2,3,4}
arr[4]==3,arr[3]>arr[4],下标放入qmax,下标2,还没过期
窗口[2..4]最大值arr[2]
- qmax={3,5}
arr[5]==3,当前qmax队尾下标4,arr[4]<=arr[5],所以弹出qmax尾部
qmax变为{2,3}
当前队尾3,arr[3]>arr[5],下标放入qmax尾
qmax变为{2,3,5}
下标2过期了,从qmax头部弹出
qmax变为{3,5}
窗口[3..5]最大值arr[3]
- qmax={6}
arr[6]==6,当前qmax队尾下标5,arr[5]<=arr[6],所以弹出qmax尾部
qmax变为{3}
下标3,arr[3]<=arr[6],弹出3,从尾部弹出
qmax变为{}
将下标6放入qmax,qmax={6}
窗口[4..6]这个下标还没过期最大值arr[6]
qmax变为{6}
- qmax={7}
arr[7]==7,当前qmax队尾下标6,arr[6]<=arr[7],所以弹出qmax尾部
qmax变为{}
下标7
qmax变为{7}
窗口[5..7]这个下标还没过期最大值arr[7]
每个下标最多进qmax一次,出qmax一次;所以遍历过程中进出双端队列的操作时间复杂度O(N),整体时间复杂度也是O(N)
附件
public class QUEUE_doubleEnded {
public static int[] get(int[] arr, int w){
if(arr == null || w < 1 || arr.length < w){
return null;
}
//
LinkedList<Integer> qmax = new LinkedList<Integer>();
int[] res=new int[arr.length -w + 1];
int index = 0;
for(int i = 0;i < arr.length; i++){
// qmax不为空 且 arr[j] <= arr[i]
while(!qmax.isEmpty() &&
arr[qmax.peekLast()] <= arr[i]){
// 把j从qmax中弹出, 继续qmax的放入规则
qmax.pollLast();
}
qmax.addLast(i);
if(qmax.peekFirst() == i-w ){
qmax.pollFirst();
}
if(i >= w-1){
res[index++] = arr[qmax.peekFirst()];
}
}
return res;
}
}