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

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

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

文章目录

一、滑动窗口的介绍

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

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

1、核心思想

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

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

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

窗口的大小 K 是固定的。

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

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

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

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

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

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

1、题目展示

2、题目示例

3、题目解析

4、算法原理

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

题目的要求是:我们在a和b这个区间里选择一些数,然后用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;
    }
};

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

三、总结

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

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

什么时候该用滑动窗口?

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

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

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

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

相关推荐
碧海银沙音频科技研究院1 小时前
基于ATS308X的无线语音交互对话功能实现
人工智能·嵌入式硬件·深度学习·算法
尹玉玺1 小时前
从原子残片到天道公理:以德谟克利特思想全貌,重新定界西方唯物认知的历史层级与边界
人工智能·算法·架构
青少儿编程课堂1 小时前
蓝桥杯·全国青少年信息素养大赛·电子学会Python/C++考级:差分数组与区间修改实战解析
c++·python·算法·bfs·信息学竞赛
重生之小比特2 小时前
【算法拾光】二分查找|二分查找 + 再排序数组中查找元素的第一个和最后一个位置
算法·leetcode·职场和发展
文丑颜不良啊2 小时前
LeetCode76~100题目解析
java·leetcode
零基础1232 小时前
基于模型的强化学习与不基于模型的强化学习:核心区别与实战选择
python·算法
罗西的思考13 小时前
【Agentic RL】Dressage Staleness 控制深度分析
人工智能·算法·机器学习
quaer13 小时前
弗洛伊德算法--判圈法寻找环的入口O(n) O(1)
数据结构·算法
文丑颜不良啊15 小时前
LeetCode51~75题目解析
leetcode
高晶15 小时前
无乘法器实现LC二阶滤波器:基于移位运算的快速算法与四种精度推导
算法·设计模式·程序员