思路
滑动窗口,使用栈来保存临时的最大值。
栈中的元素是个数组max[2].
max[0]用于保存临时的最大值,max[1]保存该临时最大值的坐标。
每次滑动窗口时会有3种情况:
- 第一种:新加入的数字比当前的最大值大,则更新stack的栈顶元素为新加入的数字
- 第二种:新加入数字后,原来的最大值滑出当前窗口,这种情况就重新计算一下当前窗口下的最大值
- 第三种:新加入的数字没有当前的最大值大,且当前的最大值没有滑出当前窗口,则直接去当前的最大值。
时间复杂度:
最坏的情况下,数组是个递减的数组,时间复杂度为O(n^2)
最优的情况下,数组基本是个递增的数组,时间复杂度为O(n)
空间复杂度:O(1)
第二种方法:使用Deque
Duque的队列中,从左到右保存的是当前窗口中元素按照从大到小的降序排列,即最左边是当前窗口中的最大值的坐标,最右边是当前窗口中最小值的坐标。
时间复杂度O(n)
空间复杂度O(k) ,因为整个Deque队列最多保存整个当前窗口的所有元素
提交代码:
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
if(nums==null||nums.length==0) return nums;
int[] res=new int[nums.length-k+1];
Stack<int[]> s=new Stack<>();
int pos=0,max=Integer.MIN_VALUE,n=nums.length;
for(int i=0;i<k;i++) {
if(nums[i]>max) {
max=nums[i];
pos=i;
}
}
int[] maxStart= {max,pos};
s.push(maxStart);
res[0]=max;
for(int i=1;i<=n-k;i++) {
if(!s.isEmpty()&&nums[i+k-1]>s.peek()[0]) {
s.pop();
int[] tmp= {nums[i+k-1],i+k-1};
s.push(tmp);
res[i]=nums[i+k-1];
}else if(!s.isEmpty()&&(i-1)==s.peek()[1]) {
s.pop();
int[] tmp=new int[2];
findNewMax(tmp,i,i+k-1,nums);
s.push(tmp);
res[i]=s.peek()[0];
}else {
res[i]=s.peek()[0];
}
}
return res;
}
public void findNewMax(int[] max,int left,int right,int[] nums) {
int tmp=Integer.MIN_VALUE;
for(int i=left;i<=right;i++) {
if(nums[i]>tmp) {
max[0]=nums[i];
max[1]=i;
tmp=nums[i];
}
}
}
}
运行结果
提交代码:使用Deque
class Solution {
public int[] maxSlidingWindow(int[] a, int k) {
if (a == null || k <= 0) {
return new int[0];
}
int n = a.length;
int[] r = new int[n-k+1];
int ri = 0;
// store index
Deque<Integer> q = new ArrayDeque<>();
for (int i = 0; i < a.length; i++) {
// remove numbers out of range k
while (!q.isEmpty() && q.peek() < i - k + 1) {
q.poll();
}
// remove smaller numbers in k range as they are useless
while (!q.isEmpty() && a[q.peekLast()] < a[i]) {
q.pollLast();
}
// q contains index... r contains content
q.offer(i);
if (i >= k - 1) {
r[ri++] = a[q.peek()];
}
}
return r;
}
}