滑动窗口的最大值(剑指Offer59)
1 题目描述
给定一个数组 nums 和滑动窗口的大小 k,请找出所有滑动窗口里的最大值。
示例:
输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3
输出: [3,3,5,5,6,7]
解释:
滑动窗口的位置 最大值
[1 3 -1] -3 5 3 6 7 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7
2 暴力法解题思路
方法一:暴力法,两层循环,第一层循环遍历数组,指示每一层窗口的起始位置,第二层循环遍历窗口找出最大值。
窗口数量:count=nums.length-k+1;即为求解数组大小。
最后一个窗口的地址:nums.length-k,即第一层循环结束的条件。
算法流程:
- 标记第一个窗口左端位置
start(初始为0) - 从
start至nums.length-k位置找到最大值 - 将最大值存入解数组
x[start]=max start++,重复1-3;
3 代码
public int[] maxSlidingWindow(int[] nums, int k) {
if(nums.length<1||k<1){
return new int[0];
}
int start = 0;
int count = nums.length-k+1;
int[] x = new int[count];
while(start<=nums.length-k){
int max = nums[start];
for(int j = start;j<start+k;j++){
//找出最大的
if (max<nums[j]){
max=nums[j];
}
}
x[start]=max;
start++;
}
return x;
}
4 复杂度分析
第一层循环遍历数组直到nums.length-k+1第二层循环遍历窗口k;因此时间复杂度为:
(
n
u
m
s
.
l
e
n
g
t
h
−
k
+
1
)
∗
k
=
(
n
−
k
+
1
)
∗
k
=
n
k
−
k
2
+
k
=
O
(
n
k
)
(nums.length-k+1)*k=(n-k+1)*k=nk-k^2+k=O(nk)
(nums.length−k+1)∗k=(n−k+1)∗k=nk−k2+k=O(nk)
5 优化思路
寻找窗口最大值需要的时间为O(k),而第一层遍历数组是无法避免的,因此本题重点要将寻找窗口内最大值的时间复杂度降低为O(1)。
可采用双端队列,窗口没移动一次保证队列中元素非严格递减,最大的元素在队首,当队首元素与将被移出的元素nums[i-1]相等时,队首元素出队。并将队内所有小于将要被包含的元素nums[i]出队并将该元素从队尾入队,保证队内元素递减
算法流程:
- 形成第一个窗口,并形成队列保证队列元素单调递减,将队首元素加入结果集
- 形成窗口后,当队首元素与将被移出的元素
nums[i-1]相等时,队首元素出队 - 将队内所有小于将要被包含的元素
nums[i]出队并将该元素从队尾入队,保证队内元素递减 - 将队首元素加入结果集
代码:
public int[] maxSlidingWindow(int[] nums, int k) {
if(nums.length<1||k<1){
return new int[0];
}
int count = nums.length-k+1;
int last = nums.length-k;
LinkedList<Integer> qu = new LinkedList<>();
int[] res = new int[count];
//形成窗口
for(int i = 0;i<=k-1;i++){
while(qu.size()!=0&&qu.getLast()<nums[i]){
qu.removeLast();
}
qu.addLast(nums[i]);
}
res[0]=qu.getFirst();
for(int i = 1,j=k;i<=last;i++,j++){
if(nums[i-1]==qu.getFirst()){
qu.removeFirst();
}
while(qu.size()!=0&&qu.getLast()<nums[j]){
qu.removeLast();
}
qu.addLast(nums[j]);
res[i]=qu.getFirst();
}
return res;
}
复杂度分析:
时间复杂度 O(n) : 其中 n 为数组 nums 长度;线性遍历 nums 占用 O(n);每个元素最多仅入队和出队一次,因此单调队列 deque占用O(2n)。
空间复杂度 O(k) : 双端队列deque 中最多同时存储k个元素(即窗口大小)。
本文介绍了如何解决滑动窗口最大值的问题,首先通过暴力法给出基础解法,然后通过优化思路,利用双端队列(deque)将时间复杂度降低到O(n),实现了线性时间复杂度的解决方案。此方法在处理大规模数据时更为高效。
336

被折叠的 条评论
为什么被折叠?



