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)。

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

相关推荐
沐怡旸7 小时前
【算法】【链表】328.奇偶链表--通俗讲解
算法·面试
掘金安东尼10 小时前
Amazon Lambda + API Gateway 实战,无服务器架构入门
算法·架构
码流之上11 小时前
【一看就会一写就废 指间算法】设计电子表格 —— 哈希表、字符串处理
javascript·算法
快手技术13 小时前
快手提出端到端生成式搜索框架 OneSearch,让搜索“一步到位”!
算法
CoovallyAIHub1 天前
中科大DSAI Lab团队多篇论文入选ICCV 2025,推动三维视觉与泛化感知技术突破
深度学习·算法·计算机视觉
NAGNIP1 天前
Serverless 架构下的大模型框架落地实践
算法·架构
moonlifesudo1 天前
半开区间和开区间的两个二分模版
算法
moonlifesudo1 天前
300:最长递增子序列
算法
CoovallyAIHub2 天前
港大&字节重磅发布DanceGRPO:突破视觉生成RLHF瓶颈,多项任务性能提升超180%!
深度学习·算法·计算机视觉
CoovallyAIHub2 天前
英伟达ViPE重磅发布!解决3D感知难题,SLAM+深度学习完美融合(附带数据集下载地址)
深度学习·算法·计算机视觉