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

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

相关推荐
吃好睡好便好3 小时前
在Matlab中绘制横直方图
开发语言·学习·算法·matlab
仰泳之鹅4 小时前
【C语言】自定义数据类型2——联合体与枚举
c语言·开发语言·算法
x_yeyue6 小时前
三角形数
笔记·算法·数论·组合数学
Mr. zhihao7 小时前
深入解析redis基本数据结构
数据结构·数据库·redis
念何架构之路7 小时前
Go语言加密算法
数据结构·算法·哈希算法
AI科技星7 小时前
《数学公理体系·第三部·数术几何》(2026 年版)
c语言·开发语言·线性代数·算法·矩阵·量子计算·agi
失去的青春---夕阳下的奔跑7 小时前
560. 和为 K 的子数组
数据结构·算法·leetcode
黎阳之光8 小时前
黎阳之光:以视频孪生重构智慧医院信息化,打造高标项目核心竞争力
大数据·人工智能·物联网·算法·数字孪生
丷丩8 小时前
三级缓存下MVT地图瓦片服务性能优化策略
算法·缓存·性能优化·gis·geoai-up
m0_629494738 小时前
LeetCode 热题 100-----25.回文链表
数据结构·算法·leetcode·链表