239. 滑动窗口最大值 - 力扣(LeetCode)
题解:
题解
这道题让我们求解窗口内的最大值;
此时我们的暴力解法就是每次更新窗口的时候就遍历一下窗口内的值(超时);
然后进行优化,就是我们用一个大根堆进行值得存储,每次进出窗口得值都同步给大根堆,然后每次大根堆得堆顶元素即可(但是也超时我,我会将超时得截图放在下面)
题解思路 :最后再进行优化:超时的原因是当k太大时,我们得堆维护了很多没要必要的值,比如1,3,-1;当我们将3加入得时候,我们肯定知道1不可能再是最大值了,因为刚加入得值3比1大;因此我们在将3加入得时候就可以把比3小而且在3前面的值全部踢出去;
之后再加入-1,这个-1虽然比3小,但是他在3后面,因此需要加入堆中(因为3在-1前面肯定要先出去,那么此时最大值就是-1了);
这样下来之后,我们的堆中维护的都是可能成为最大值的值;并且,通过上述逻辑,我们可以知道队首的元素肯定是最大值(因为当我们加入一个值的时候,会将他前面并且比他小的元素都给剔除),因此就不需要创建大根堆去维护值了,使用双向队列或者列表即可。
代码逻辑:
首先我们要创建一个列表,每次加入元素的时候都需要首先将移除窗口的元素从列表中移除,然后从末尾遍历元素,如果队尾有值比他小那么就给踢掉,直到遇到比当前值大的元素;
随后就是加入元素,并且获取链表的头节点,就是当前窗口的最大值;
链表的方法:
获取头节点的值:list.get(0);
获取尾节点的值:list.get(list.size() -1)
删除某个位置的节点: list.remove(index);
代码
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
//目前只需要维护可能的最大值,弹出堆顶元素即可
List<Integer> list = new LinkedList<>();
int[] r = new int[nums.length - k + 1];
int index = 0;
for(int i = 0 ; i < nums.length;i++){
if(i - k >= 0 && nums[i - k] == list.get(0)) list.remove(0);
int cur = 0;
while(list.size() != 0 && list.get(list.size() -1 ) < nums[i]){
list.remove(list.size() - 1);
}
list.add(nums[i]);
if(i >= k - 1)
r[index++] = list.get(0);
}
return r;
}
}