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 小时前
机器学习-KNN算法
人工智能·算法·机器学习
闪电麦坤954 小时前
数据结构:排序算法的评判标准(Criteria Used For Analysing Sorts)
数据结构·算法·排序算法
爱coding的橙子4 小时前
每日算法刷题Day65:8.27:leetcode dfs11道题,用时2h30min
算法·leetcode·深度优先
不懂机器人4 小时前
linux网络编程-----TCP服务端并发模型(epoll)
linux·网络·tcp/ip·算法
Mercury_Lc5 小时前
【链表 - LeetCode】25. K 个一组翻转链表
数据结构·leetcode·链表
地平线开发者5 小时前
理想汽车智驾方案介绍 3|MoE+Sparse Attention 高效结构解析
算法·自动驾驶
小O的算法实验室6 小时前
2025年KBS SCI1区TOP,矩阵差分进化算法+移动网络视觉覆盖无人机轨迹优化,深度解析+性能实测
算法·论文复现·智能算法改进
艾莉丝努力练剑7 小时前
【C语言16天强化训练】从基础入门到进阶:Day 11
c语言·学习·算法
浩少7029 小时前
LeetCode-22day:多维动态规划
算法·leetcode·动态规划