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

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

相关推荐
sheeta19985 小时前
LeetCode 每日一题笔记 日期:2025.11.24 题目:1018. 可被5整除的二进制前缀
笔记·算法·leetcode
gfdhy11 小时前
【c++】哈希算法深度解析:实现、核心作用与工业级应用
c语言·开发语言·c++·算法·密码学·哈希算法·哈希
百***060111 小时前
SpringMVC 请求参数接收
前端·javascript·算法
weixin_4577600011 小时前
Python 数据结构
数据结构·windows·python
一个不知名程序员www12 小时前
算法学习入门---vector(C++)
c++·算法
云飞云共享云桌面12 小时前
无需配置传统电脑——智能装备工厂10个SolidWorks共享一台工作站
运维·服务器·前端·网络·算法·电脑
明洞日记12 小时前
【数据结构手册002】动态数组vector - 连续内存的艺术与科学
开发语言·数据结构·c++
福尔摩斯张12 小时前
《C 语言指针从入门到精通:全面笔记 + 实战习题深度解析》(超详细)
linux·运维·服务器·c语言·开发语言·c++·算法
fashion 道格12 小时前
数据结构实战:深入理解队列的链式结构与实现
c语言·数据结构
橘颂TA13 小时前
【剑斩OFFER】算法的暴力美学——两整数之和
算法·leetcode·职场和发展