#P3742. 第3题-滑动窗口最大值
-
ID: 3085
Tried: 50
Accepted: 25
Difficulty: 5
所属公司 :
新凯来
时间 :2025年9月20日-算法岗
-
算法标签>双端队列
第3题-滑动窗口最大值
思路(单调队列)
核心数据结构:维护一个下标的双端队列 dq,使得队列中对应的值严格单调递减。这样队首始终是当前窗口的最大值下标。
对每个下标 i 执行:
- 删除过期:如果 dq 的队首下标小于当前窗口的左边界(即 dq.front()≤i−k),就从队首弹出。
- 维护单调性:当 nums[dq.back()]≤nums[i] 时,从队尾弹出,直到队列对应值重新递减。
- 加入新元素:把 i 加到队尾。
- 当 i≥k−1 时,窗口形成,答案加入 nums[dq.front()]。
C++
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
if (!(cin >> n)) return 0;
vector<int> nums(n);
for (int i = 0; i < n; ++i) cin >> nums[i];
int k; cin >> k;
deque<int> dq; // 存放下标,队列对应的值单调递减
vector<int> ans;
for (int i = 0; i < n; ++i) {
// 1) 删除过期元素:队首下标已经离开窗口
while (!dq.empty() && dq.front() <= i - k) dq.pop_front();
// 2) 维护单调性:队尾对应值小于等于当前值则弹出
while (!dq.empty() && nums[dq.back()] <= nums[i]) dq.pop_back();
// 3) 加入当前下标
dq.push_back(i);
// 4) 当窗口形成后,记录最大值
if (i >= k - 1) ans.push_back(nums[dq.front()]);
}
// 输出
for (int i = 0; i < (int)ans.size(); ++i) {
if (i) cout << ' ';
cout << ans[i];
}
cout << '\n';
return 0;
}
Python
import sys
from collections import deque
def main():
data = sys.stdin.read().strip().split()
if not data:
return
it = iter(data)
n = int(next(it))
nums = [int(next(it)) for _ in range(n)]
k = int(next(it))
dq = deque() # 存下标,保持对应值单调递减
out = []
for i, x in enumerate(nums):
# 1) 删过期:队首已经离开窗口
while dq and dq[0] <= i - k:
dq.popleft()
# 2) 保持单调:队尾对应值 <= 当前值,则弹出
while dq and nums[dq[-1]] <= x:
dq.pop()
# 3) 加入当前下标
dq.append(i)
# 4) 窗口形成后取最大值
if i >= k - 1:
out.append(str(nums[dq[0]]))
print(" ".join(out))
if __name__ == "__main__":
main()
Java
import java.io.*;
import java.util.*;
/** 滑动窗口最大值:单调队列(存下标) */
public class Main {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String s = br.readLine();
if (s == null || s.trim().isEmpty()) return;
int n = Integer.parseInt(s.trim());
StringTokenizer st = new StringTokenizer(br.readLine());
int[] nums = new int[n];
for (int i = 0; i < n; i++) nums[i] = Integer.parseInt(st.nextToken());
int k = Integer.parseInt(br.readLine().trim());
Deque<Integer> dq = new ArrayDeque<>(); // 存下标,保持对应值单调递减
StringBuilder sb = new StringBuilder();
for (int i = 0; i < n; i++) {
// 1) 删除过期:队首下标已不在窗口
while (!dq.isEmpty() && dq.peekFirst() <= i - k) dq.pollFirst();
// 2) 维护单调:队尾对应值 <= 当前值,弹出
while (!dq.isEmpty() && nums[dq.peekLast()] <= nums[i]) dq.pollLast();
// 3) 加入当前下标
dq.offerLast(i);
// 4) 窗口形成,取最大值
if (i >= k - 1) {
if (sb.length() > 0) sb.append(' ');
sb.append(nums[dq.peekFirst()]);
}
}
System.out.println(sb.toString());
}
}
题目内容
给你一个整数数组nums,有一个大小为k的滑动窗口从数组的最左侧移动到数组的最右侧,你只可以看到在滑动窗口内的k个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值。
输入描述
第一行输入1个整数,分别为{n} 的个数,1<=nums.length<=105
第二行输入数列{n},用空格隔开,−104<=nums1<=104
第三行输入1个整数,滑窗长度,1<=k<=nums.length
输出描述
结果输出一行,数组每个滑窗的最大值
样例1
输入
8
1 3 -1 -3 5 3 6 7
3
输出
3 3 5 5 6 7