P3397扫描问题:使用单调队列优化代码解决超时问题
### 🍎 问题分析 原代码使用暴力法,每次移动窗口都遍历窗口内的所有元素来寻找最大值,时间复杂度达到了 $O(nk)$,当数据规模较大时(本题 $1\leq k\leq n\leq 2\times10^6$ ),这样的复杂度很容易导致超时(TLE)。为了优化时间复杂度,我们可以使用单调队列来解决这个问题,它可以将时间复杂度优化到 $O(n)$。 ### 💡 单调队列思路 单调队列是一种特殊的队列,它保证队列中的元素是单调递增或单调递减的。在本题中,我们使用单调递减队列,队列头部始终存储当前窗口内的最大值。 ### 📦 优化后的代码 ```cpp #include <iostream> #include <vector> #include <deque> using namespace std; // 函数用于找出每个窗口内的最大值 void maxSlidingWindow(const vector<int>& nums, int k) { int n = nums.size(); deque<int> dq; // 定义单调递减队列 // 先处理前 k 个元素,初始化队列 for (int i = 0; i < k; ++i) { // 当队列不为空且当前元素大于队列尾部元素时,弹出队列尾部元素 while (!dq.empty() && nums[i] >= nums[dq.back()]) { dq.pop_back(); } dq.push_back(i); // 将当前元素下标加入队列 } // 输出第一个窗口的最大值 cout << nums[dq.front()] << endl; // 处理剩余的元素 for (int i = k; i < n; ++i) { // 如果队列头部元素已经不在当前窗口内,弹出队列头部元素 if (!dq.empty() && dq.front() == i - k) { dq.pop_front(); } // 当队列不为空且当前元素大于队列尾部元素时,弹出队列尾部元素 while (!dq.empty() && nums[i] >= nums[dq.back()]) { dq.pop_back(); } dq.push_back(i); // 将当前元素下标加入队列 // 输出当前窗口的最大值 cout << nums[dq.front()] << endl; } } int main() { int n, k; // 读取数组长度 n 和窗口长度 k cin >> n >> k; vector<int> nums(n); // 读取数组中的元素 for (int i = 0; i < n; ++i) { cin >> nums[i]; } maxSlidingWindow(nums, k); return 0; } ``` ### 📋 代码解释 1. **初始化单调队列**:在 `maxSlidingWindow` 函数中,定义一个双端队列 `dq` 用于存储元素下标。首先处理前 `k` 个元素,当队列不为空且当前元素大于队列尾部元素时,弹出队列尾部元素,保证队列的单调性,最后将当前元素下标加入队列。 2. **输出第一个窗口的最大值**:队列头部元素的下标对应的元素就是当前窗口的最大值,输出该值。 3. **移动窗口并更新队列**:对于 `k` 到 `n - 1` 的元素,先检查队列头部元素是否已经不在当前窗口内,如果是则弹出队列头部元素。然后进行与初始化时相同的操作,保持队列的单调性。最后输出当前窗口的最大值。 ### ⚙️ 复杂度分析 - **时间复杂度**:$O(n)$,每个元素最多进队和出队一次。 - **空间复杂度**:$O(k)$,队列中最多存储 `k` 个元素。 ### 💡 开发建议 - **错误处理**:可以添加对输入的合法性检查,例如 `n` 和 `k` 是否满足题目要求的范围。 - **代码复用**:将单调队列的逻辑封装得更通用,方便在其他类似问题中复用。 - **边界情况考虑**:尤其是在处理队列的进出操作时,要仔细考虑边界情况,避免出现越界等错误。 ######[AI写代码神器 | 963点数解答 | 2026-08-15 16:12:03]
- JSP 实现商品展示模块:分页、搜索、交互与美观界面全搞定!(字节豆包 | 19点数解答 | 2024-12-13 15:00:43)435
- C3期末:精准求解 3 - 20 范围内数列第 k 项值及注意要点(字节豆包 | 242点数解答 | 2025-06-15 11:26:19)228
- C++求解:查找3 - 20项数列第k项值及注意要点(字节豆包 | 325点数解答 | 2025-06-15 11:27:11)256
- PyCharm 中用 Selenium 编写自动化测试脚本,轻松登录 eShop 测试平台并点击“我的订单”(字节豆包 | 304点数解答 | 2024-11-06 15:38:30)535
- C#工程师必知:数组、链表、哈希、队列、栈数据结构优缺点大揭秘! (百度文心 | 561点数解答 | 2023-11-09 17:56:30)329
- 揭秘!十进制整数转其他进制用啥存储结构最合适?答案竟是它!(字节豆包 | 57点数解答 | 2024-11-13 01:21:11)324
- Java 实现仿 Windows 资源管理器:文件管理器功能全解析与代码示例(字节豆包 | 623点数解答 | 2025-01-01 14:59:04)331
- 用队列操作算法模拟周末舞会舞伴配对问题及代码实现(DeepSeek | 601点数解答 | 2025-05-18 11:27:45)233
- 解析React 15与Vue 2:从O(n^3)到O(n),Diff算法时间复杂度计算及性能对比 (阿里通义 | 379点数解答 | 2023-11-09 01:49:19)438
- 缜密逻辑,全新无名杀“风餐”技能代码精心打造与深度解析 (字节豆包 | 469点数解答 | 2025-04-05 11:37:06)391
- 精准优化:明确需求,开启高效提升之旅! (字节豆包 | 52点数解答 | 2026-02-09 16:44:46)162
- 代码再升级:优化版“获取dump”代码,多机制保障数据读取与保存(字节豆包 | 734点数解答 | 2026-02-10 01:23:31)155