题目
给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。返回滑动窗口中的最大值。
方法一:优先队列(大根堆)
在优先队列中存储二元组 (num,index),表示元素 num 在数组中的下标为 index,进行排序。
new Comparator<int[]>()
1 3 2 4 7 为第0列的所有行
2 5 7 9 8 为第1列的所有行
- return a[0]-b[0] 就是对第0列的数据进行排序,a[0]可以理解成 1 ,b[0]可以理解成 3
- return b[1]-a[1] 就是对第1列的数据进行排序
a-b,表示升序,a代表第一个数,b代表第二个数;b-a 表示降序。
public int[] maxSlidingWindow(int[] nums, int k) {
int n=nums.length;
PriorityQueue<int[]> pq=new PriorityQueue<int[]>(new Comparator<int[]>(){
public int compare(int[] pair1,int[] pair2){
return pair1[0]!=pair2[0]?pair2[0]-pair1[0]:pair2[1]-pair1[1];
}
});
for(int i=0;i<k;++i){
pq.offer(new int[]{nums[i],i});
}
int[] ans =new int[n-k+1];
ans[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();
}
ans[i-k+1]=pq.peek()[0];
}
return ans;
}
复杂度分析
时间复杂度: O(nlogn),其中 n 是数组 nums 的长度。
空间复杂度: O(n),即为优先队列需要使用的空间。
方法二:单调队列
左侧元素小于右侧元素,则可永久删除
public int[] maxSlidingWindow(int[] nums, int k) {
int n =nums.length;
Deque<Integer> dequeu=new LinkedList<Integer>();
for(int i=0;i<k;++i){
while(!dequeu.isEmpty()&&nums[i]>=nums[dequeu.peekLast()]){
dequeu.pollLast();
}
dequeu.offerLast(i);
}
int[] ans=new int[n-k+1];
ans[0]=nums[dequeu.peekFirst()];
for(int i=k;i<n;++i){
while(!dequeu.isEmpty()&&nums[i]>=nums[dequeu.peekLast()]){
dequeu.pollLast();
}
dequeu.offerLast(i);
while(dequeu.peekFirst()<=i-k){
dequeu.pollFirst();
}
ans[i-k+1]=nums[dequeu.peekFirst()];
}
return ans;
}
复杂度分析
时间复杂度:O(n),其中 nn 是数组nums 的长度。
空间复杂度:O(k)。