【算法】滑动窗口解决力扣『将x减到0的最操作数』问题

🎬 个人主页MSTcheng · CSDN
🌱 代码仓库MSTcheng · Gitee
🔥 精选专栏 : 《C语言
数据结构
《算法学习》
C++由浅入深

💬座右铭: 路虽远行则将至,事虽难做则必成!

文章目录

一、滑动窗口的介绍

滑动窗口(Sliding Window) 是一种处理数组或字符串类算法题的常用优化技巧。它将嵌套的循环O(N^2)优化成单层循环O(N),从而显著的减低时间复杂度。

可以把它想象成一段在数组上滑动的"透明玻璃框"。

1、核心思想

滑动窗口主要用于解决连"续子序列"的问题

  • 传统暴力法: 枚举每一个起点,再从起点开始向后枚举,每一次都要重新去画一个框。
  • 滑动窗口法: 只需要维护两个指针leftright(leftright分别为左边界和右边界),通过right向右移动来吸收新元素,left++来排除旧元素。

2.、窗口的分类
(1) 固定窗口

窗口的大小 K 是固定的。

复制代码
场景:求长度为K的子数组的最大平均值。
操作:right每移动一步,left 也同步移动一步,保持 right - left + 1 == K。

(2) 可变窗口(最常见)

窗口的大小根据条件动态收缩。

复制代码
场景:求和为S的最短子数组;求不重复字符的最长子串。
操作:right 不断向右扩大窗口,当窗口内条件不再满足(或超过)要求时,left 开始向右移动收缩窗口。

2、滑动窗口与传统暴力的区别

二、利用滑动窗口解决将x减到0的最小操作数问题

1、题目展示

2、题目示例

3、题目解析

4、算法原理

思考一下:如果我们直接的按照题目的要求去选择数的话我们会发现有非常多种选法,比如我们可以按顺序从左往右依次去选择;或者直接从中间开始;也可以一左一右来选择。像这样正面操作比较困难我们就取它的反面来实现。

题目的要求是:我们在ab这个区间里选择一些数,然后用x减去这些数等于0的最小选择个数(这里从左右两倍选择来举例选择方法有很多种这是其中一种)。那我们的就取题目的反面,去找一个最长的区间,区间的数加起来等于sum-x,这里的sum是整个数组的总和。

为什么能这样?

思考一下,我现在的问题已经从我要去选择一些数,使得x减去这些数等于0,并且选择的数的个数越少越好的问题,转化成了找一个最长区间,使得这个区间的数加起来正好等于sum-x的问题,因为我们找到了一个区间等于sum-x,那么上图a区间和b区间的数加起来一定是等于x的,因为sum-x又加上x才等于sum!!!

具体的操作步骤:

5、代码示例

cpp 复制代码
class Solution {
public:
    int minOperations(vector<int>& nums, int x) {
        int size=nums.size();//计算nums的大小
        //定义两个指针
        int left=0,right=0;
        int total=0;//nums所有元素的总和
        //先遍历nums记录所有元素的总和
        for(int i=0;i<size;i++)
        {   
            total+=nums[i];
        }
        //特殊情况的处理
        if(total<x)
        {
            //意味删除所有元素都也无法凑成x
            return -1;
        }
        
        //滑动窗口
        int target=total-x; //
        int sum=0;
        int maxlen=-1;
        while(right<size)
        {
						//进入窗口
            sum+=nums[right];
            right++;
            //出窗口的条件 sum>target
            while(sum>target)
            {
                sum-=nums[left];
                left++;
            }
					 //跳出循环此时sum可能小于target也可能等于target
            //只有sum==target时更新结果
            if(sum==target)
            {
                int currlen=right-left;
                maxlen=max(currlen,maxlen);
            }
        }
        //跳出循环 要注意窗口内部的元素都不符合要求 所以maxlen不会更新
        if(maxlen==-1)
        {
            return -1;
        }
        //当right遍历到最后循环结束此时已经记录下了中间最大的长度 使用size-maxlen得到最小区间
        return size-maxlen;
    }
};

注意:totalnums所有元素的总和而sum是窗口leftright所包含的区间的总和!,以及最后maxlen的判断,maxlen默认为-1,如果进入循环都找不到一个sum等于target那么也就意味着maxlen没有更新,说明找不到一个区间ab使得x减去这个区间的数等于0,此时直接返回-1即可!

三、总结

本题我们使用了滑动窗口来解决,滑动窗口的特征是:

  1. 两个指针都向同一个方向去运动,且指针不会回退。
  2. 滑动窗口的步骤就是:进窗口,判断,出窗口,更新结果这几个步骤。

什么时候该用滑动窗口?

当你看到题目包含以下关键词时,可以考虑:

1、连续(子数组、子串)。

2、求最值(最长、最短、最大和)。

3、约束条件(和等于 K、不包含重复字符)。

相关推荐
数研小生8 小时前
构建命令行单词记忆工具:JSON 词库与艾宾浩斯复习算法的完美结合
算法·json
芒克芒克8 小时前
LeetCode 题解:除自身以外数组的乘积
算法·leetcode
Python 老手9 小时前
Python while 循环 极简核心讲解
java·python·算法
@Aurora.9 小时前
优选算法【专题九:哈希表】
算法·哈希算法·散列表
爱看科技9 小时前
微美全息(NASDAQ:WIMI)研究拜占庭容错联邦学习算法,数据安全与隐私保护的双重保障
算法
qq_417129259 小时前
C++中的桥接模式变体
开发语言·c++·算法
YuTaoShao10 小时前
【LeetCode 每日一题】3010. 将数组分成最小总代价的子数组 I——(解法二)排序
算法·leetcode·排序算法
XH华12 小时前
备战蓝桥杯,第七章:函数与递归
职场和发展·蓝桥杯
吴维炜12 小时前
「Python算法」计费引擎系统SKILL.md
python·算法·agent·skill.md·vb coding
Σίσυφος190013 小时前
PCL Point-to-Point ICP详解
人工智能·算法