LeetCode 239. 滑动窗口最大值

题目描述

给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k的子数组的个数

子数组是数组中元素的连续非空序列。

示例

示例 1:

复制代码
输入:nums = [1,1,1], k = 2
输出:2

示例 2:

复制代码
输入:nums = [1,2,3], k = 3
输出:2

解法

1.暴力算法
cpp 复制代码
class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        if(nums.empty() || k == 0) return {};
        if(k == 1) return nums;
        vector <int> ans;
        for(int i = 0;i <= nums.size() - k;i ++){
            int max_val = nums[i];
            for(int j = i;j < i + k;j ++){
                max_val = max(max_val,nums[j]);
            }
            ans.push_back(max_val);
        } 
        return ans;
    }
};

暴力算法的时间复杂度为0(nk),大部分案例都通过不了。

2.暴力算法(优化)
cpp 复制代码
class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        if(nums.empty() || k == 0) return {};
        if(k == 1) return nums;
        
        vector<int> ans;
        int max_val = nums[0], max_idx = 0;
        
        // 初始化第一个窗口的最大值
        for(int i = 1; i < k; i++){
            if(nums[i] >= max_val){
                max_val = nums[i];
                max_idx = i;
            }
        }
        ans.push_back(max_val);
        
        // 处理后续窗口
        for(int i = 1; i <= nums.size() - k; i++){  
            int right = i + k - 1;  // 新窗口的右边界
            
            // 如果最大值还在窗口内
            if(max_idx >= i) {
                if(nums[right] > max_val) {  // 新元素更大
                    max_val = nums[right];
                    max_idx = right;
                }
                ans.push_back(max_val);
            } 
            // 最大值已移出窗口
            else {
                // 重新计算当前窗口的最大值
                max_val = nums[i];
                max_idx = i;
                for(int j = i + 1; j <= right; j++){
                    if(nums[j] >= max_val){
                        max_val = nums[j];
                        max_idx = j;
                    }
                }
                ans.push_back(max_val);
            }
        }
        
        return ans;
    }
};

通过判断窗口滑动后最大值是否还在窗口中,并且和新传入的窗口右边界元素进行比较,减少了大量判断,对纯暴力算法进行了优化,但是最坏的时间复杂度依然为0(nk),仍然有两组案例通过不了。

3.双端队列

思路:

仔细阅读该题目不难发现,题目和双端队列的定义很相似,于是考虑引入双端队列,可以简化编程,降低时间复杂度。

cpp 复制代码
class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        if(nums.empty() || k == 0) return {};
        
        vector<int> ans;
        deque<int> dq; // 存储索引
     
        for(int i = 0; i < nums.size(); i++) {
            // 移除超出窗口范围的元素
            if(!dq.empty() && dq.front() == i - k) {
                dq.pop_front();
            }
            
            // 移除队列中比当前元素小的元素(关键)
            while(!dq.empty() && nums[dq.back()] < nums[i]) {
                dq.pop_back();
            }
            
            // 添加当前元素索引
            dq.push_back(i);
            
            // 当窗口形成时,添加最大值
            if(i >= k - 1) {
                ans.push_back(nums[dq.front()]);
            }
        }
        return ans;
    }
};

时间复杂度:O(n),空间复杂度:O(k)。

核心优化思想:单调队列,这种方法的巧妙之处在于它将找最大值的过程分摊到了每个元素的处理中,而不是为每个窗口单独计算,从而实现了线性时间复杂度。

相关推荐
hetao173383716 分钟前
2025-10-30 ZYZOJ Star(斯达)模拟赛 hetao1733837的record
c++·算法
无敌最俊朗@16 分钟前
C++ 值类别与移动语义详解(精简版)
java·数据结构·算法
lingran__1 小时前
算法沉淀第十一天(序列异或)
c++·算法
一匹电信狗1 小时前
【C++】红黑树详解(2w字详解)
服务器·c++·算法·leetcode·小程序·stl·visual studio
岑梓铭1 小时前
《考研408数据结构》第六章(5.5树的应用)复习笔记
数据结构·笔记·考研·408·ds
不觉晚秋1 小时前
极限挑战之一命速通哈夫曼树
c语言·数据结构··哈夫曼树
寂静山林2 小时前
UVa 11853 Paintball
算法
第七序章2 小时前
【C + +】C++11 (下) | 类新功能 + STL 变化 + 包装器全解析
c语言·数据结构·c++·人工智能·哈希算法·1024程序员节
Theodore_10222 小时前
深度学习(10)模型评估、训练与选择
人工智能·深度学习·算法·机器学习·计算机视觉
五条凪2 小时前
Verilog-Eval-v1基准测试集搭建指南
开发语言·人工智能·算法·语言模型