思路一:优先队列
用二维优先队列存储一个数的值和下标,维持这个优先队列是大根堆,堆顶就是当前窗口的最大值,当最大值的下标超出窗口范围,pop出去
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
PriorityQueue<int[]>pq=new PriorityQueue<>
((int[]a,int[]b)->b[0]-a[0]);//从大到小排
int n=nums.length;
if(n==0) return new int[0];
for(int i=0;i<k;i++){
pq.offer(new int[]{nums[i],i});
}
int[] res=new int[n-k+1];
res[0]=pq.peek()[0];
for(int i=k;i<n;i++){
pq.offer(new int[]{nums[i],i});
while(pq.peek()[1]<=i-k){
pq.poll();
}
res[i-k+1]=pq.peek()[0];
}
return res;
}
}
思路二:优化 --> 单调(递减)队列
如果i < j
,并且满足nums[i]≤nums[j]
,
当滑动窗口向右移动时,只要 i
还在窗口中,那么 j
一定也还在窗口中,因此,由于 nums[j]
的存在,nums[i]
一定不会是滑动窗口中的最大值了,我们可以将 nums[i]
永久地移除。
使用一个单调队列存储所有还没有被移除的下标。在队列中,这些下标按照从小到大的顺序被存储,并且它们在数组 nums 中对应的值是严格单调递减的(相等的话下标小的也可以被移除)。
当滑动窗口向右移动时,把一个新的元素放入队列中。将新的元素与队尾的元素相比较,如果前者大于等于后者,那么队尾的元素就可以被永久地移除,我们将其弹出队列。此时队首下标对应的元素就是滑动窗口中的最大值。
同时,与方法一中相同的是,此时的最大值可能在滑动窗口左边界的左侧,所以还是需要检查下标。
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
int n=nums.length;
List<Integer>list=new ArrayList<>();
for(int i=0;i<k;i++){
while(!list.isEmpty() && nums[i]>nums[list.get(list.size()-1)]){
list.remove(list.size()-1);
}
list.add(i);
}
int[] ans=new int[n-k+1];
ans[0]=nums[list.get(0)];
for(int i=k;i<n;i++){
while(!list.isEmpty() && nums[i]>nums[list.get(list.size()-1)]){
list.remove(list.size()-1);
}
list.add(i);
while(list.get(0)<=i-k) list.remove(0);
ans[i-k+1]=nums[list.get(0)];
}
return ans;
}
}