leetcode239.滑动窗口的最大值
原题目
思路
思路一:
自己刚刚写的时候,是用优先队列写的,每次从队列中取出的都是当前队列中的最大值,加到结果中去。代码如下:
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
if(nums.length==0)
return new int[0];
Comparator<Integer> cmp = (e1,e2)->{
return e2-e1;
};
Queue<Integer> q1 = new PriorityQueue<Integer>(cmp);
int[] ans = new int[nums.length-k+1];
for(int i = 0;i<k;i++){
q1.add(nums[i]);
}
ans[0] =q1.peek();
for(int i = 1;i<nums.length-k+1;i++){
q1.remove(nums[i-1]);
q1.add(nums[k+i-1]);
ans[i] = q1.peek();
}
return ans;
}
}
思路二
用双向队列解决,思路是这样的队列中保存的是数组中的下标,有序,每次添加元素时都需要判断结尾中的下标所对应的值是否大于此数所对应的值,不是的话,直接加到队列中,否则删除队尾中的数,直到此数在正确的位置上即可。
代码如下:
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
int len = nums.length;
if(len==0)
return new int[0];
ArrayDeque<Integer> arr = new ArrayDeque<>();
int max_id = 0;
int[] ans = new int[len-k+1];
for(int i = 0;i<k;i++){
while(!arr.isEmpty()&&nums[i]>nums[arr.getLast()]){
arr.removeLast();
}
arr.add(i);
}
ans[0] = nums[arr.getFirst()];
for(int i = k;i<len;i++){
//因为队列中的数代表的是下标,所以此处if判断的是是否将下标移除
if(!arr.isEmpty()&&arr.getFirst()<=i-k)
arr.removeFirst();
while(!arr.isEmpty()&&nums[i]>nums[arr.getLast()]){
arr.removeLast();
}
arr.add(i);
ans[i-k+1] = nums[arr.getFirst()];
}
return ans;
}
}
思路三
动态规划,真的厉害,完全想不到竟然还可以用动态规划进行解决(Orz)
声明一下图片来自leetcode中
首先将数组分块,即len%k
用left数组代表从块的左边到右边的最大值
right数组代表从块的右边到左边的最大值
解释input被分为3个部分 即[1,3,-1],[-3,5,3],[6,7];
left当访问块的开始时,直接等于即可,即当访问1时,最大即left[0]=1;
访问3时,因为比1大,所以left[1]=3,
访问-1时,因为比3小,所以left[2]=3,
访问-3时,因为为块的开始,即left[3] = -3,以此类推
而right数组则从最后一块开始,从右侧开始到左侧结束就好,以此递推就出来了
那么怎么得出结果ans数组呢?ans[i] = max(right[i],left[i+k-1])
假如正是[-1,-3,5]这三个数
当处于上面的那个状态时,right[i]就代表此时从-1开始到-1结束的最大值,即-1
left[i+k-1]就代表[-3,5]之间的最大值
代码
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
int len = nums.length;
if(len==0)
return new int[0];
int[] left = new int[len];
int[] right = new int[len];
left[0] = nums[0];
right[len-1] = nums[len-1];
for(int i = 1;i<len;i++){
if((i)%k==0){
left[i] = nums[i];
}
else{
left[i] = Math.max(left[i-1],nums[i]);
}
int ri_pos = len-i-1;
if((ri_pos+1)%k==0){
right[ri_pos] = nums[ri_pos];
}
else{
right[ri_pos] = Math.max(right[ri_pos+1],nums[ri_pos]);
}
}
int[] ans = new int[len-k+1];
for(int i = 0;i<len-k+1;i++){
ans[i] = Math.max(left[i+k-1],right[i]);
}
return ans;
}
}