算法每日双题精讲——滑动窗口(最大连续1的个数 III,将 x 减到 0 的最小操作数)

 🌟快来参与讨论💬,点赞👍、收藏⭐、分享📤,共创活力社区。 🌟

别再犹豫了!快来订阅我们的算法每日双题精讲专栏,一起踏上算法学习的精彩之旅吧!💪


 目录

💯前言

💯滑动窗口的作用

🎉最大连续 1 的个数 III 

📖题目描述

🧠解题思路

🙋这个解题思路是怎么来的呢? 

💻代码实现(以 C++ 为例) 

 📊复杂度分析

🎉将 x 减到 0 的最小操作数

📖题目描述

🧠解题思路

 🙋这个解题思路是怎么来的呢? 

💻代码实现(以 C++ 为例)

  📊复杂度分析

💯总结


💯前言

嘿,小伙伴们!在算法这个神奇的世界里,滑动窗口算法就像是一颗闪闪发光的🌟明星哦,它在解决数组和字符串相关的问题时可太厉害了!今天呢,咱们就一起来看看另外两道超经典的题目 ——“最大连续 1 的个数 III” 和 “将 x 减到 0 的最小操作数”,看看滑动窗口算法在这两道题里是怎么大显身手的🧐

当我们遇到要在给定的数据结构里找满足特定条件的子结构这类问题时,滑动窗口算法就像一把神奇的🔑钥匙,能帮我们轻松打开解题的大门哦!


💯滑动窗口的作用

滑动窗口算法可有趣啦!它用两个同向的指针来定义一个会动的 “窗口” 哦,这个窗口就像一个调皮的😜小精灵,在数组或者字符串里跑来跑去呢。通过不停地调整窗口的大小和位置,它能时刻知道窗口里面元素的情况,这样就能很快找到我们想要的子序列或者子串啦。这种方法可比那种傻傻地把所有可能的子结构都检查一遍的暴力枚举法强多啦,它能让算法的效率像火箭一样🚀飞起来呢!

滑动窗口是利用单调性,用 “同向双指针” 来实现优化的哦。简单来说呢,就是指针只向前走,不会后退哦。

👇操作步骤大概是这样滴:

  1. 先把leftright都设成0
  2. 然后把元素放进窗口里,接着判断一下,如果满足条件就缩小窗口,如果不满足就扩大窗口,
  3. 最后别忘了更新结果哦。
  4. 就这样一直重复,直到把整个数据结构都遍历完。这样就能巧妙地避开那些没必要的计算啦,是不是很聪明呢?😎

🎉最大连续 1 的个数 III 

📖题目描述

给你一个二进制数组nums和一个整数k哦,你可以把数组里最多k0变成1,然后呢,你要找出数组里连续1最多能有多少个。

 

🧠解题思路

  1. 首先,我们把两个指针leftright都放在数组的开头,再设一个count用来记录窗口里0的个数,初始值是0,还有一个maxLength用来记录最大连续1的个数,初始值是0。🧐
  2. 然后呢,我们把right指针往右移,每移一次,如果遇到0,就把count1。😜
  3. 要是countk大了,这就说明窗口里0太多啦,超过了能变的数量。这时候呢,我们就把left指针往右移。要是left指向的是0,就把count1。😏
  4. 每次移动指针之后,我们都要更新maxLength哦,它应该是当前窗口里连续1的个数(right - left + 1 - count)和之前maxLength里比较大的那个值。👍
  5. 就这样一直重复步骤 2 - 4,直到left指针走到数组的末尾。最后,我们就可以把maxLength返回啦。🎉

🙋这个解题思路是怎么来的呢? 

我们首先最容易想到解法一:暴力求解

 


 👇现在我们来分析以下数组:

 left=right=0

 

👆right指向的不是 0,就让right++,是0,就让countzero++

👆 此时countzero>k,我们计算len=right-left

 

👆然后我们让left走到让countzero恢复为k的位置 

重复以上过程直到right=nums.size() 

💻代码实现(以 C++ 为例) 

class Solution {
public:
    int longestOnes(vector<int>& nums, int k) {
        // 用于记录满足条件的最长子数组长度,初始化为0
        int len = 0;
        // 滑动窗口的右指针,初始指向数组开头
        int right = 0;
        // 滑动窗口的左指针,初始指向数组开头
        int left = 0;
        // 用于统计当前滑动窗口内0的个数,初始化为0
        int countzero = 0;

        // 只要右指针没有超出数组范围,就持续进行窗口的移动和调整操作
        while (right < nums.size()) {
            // 如果当前右指针指向的元素是0,就将窗口内0的计数加1
            if (nums[right] == 0)
                countzero++;

            // 当窗口内0的个数超过了允许的k值时,需要调整窗口
            while (countzero > k) {
                // 先将左指针向右移动一位(这里left++先使用left的值然后再自增)
                // 如果移动后左指针指向的元素是0,就将窗口内0的计数减1
                // 因为这个0即将被移出窗口,所以要相应地更新计数
                if (nums[left++] == 0)
                    countzero--;
            }

            // 更新满足条件的最长子数组长度
            // 这里right - left + 1表示当前窗口的长度
            // 通过比较当前窗口长度和之前记录的len,取较大值更新len
            len = max(len, right - left + 1);

            // 将右指针向右移动一位,继续扩大窗口以探索后续元素
            right++;
        }

        // 返回找到的满足条件的最长子数组长度
        return len;
    }
};

 📊复杂度分析

  • 时间复杂度:是O(n)哦,这里的n就是数组的长度啦。因为在最坏的情况下,right指针要把整个数组遍历一遍,left指针最多也会遍历一遍整个数组呢。😎
  • 空间复杂度:是O(1)哦,因为我们只需要几个额外的变量来存指针和一些数,这些只需要常数大小的空间呢。🧐

 


🎉将 x 减到 0 的最小操作数

📖题目描述

给你一个整数数组nums和一个整数x哦。你要在数组里选一个连续的子数组,让这个子数组里所有数的和等于x,然后找出满足这个条件的最小操作数(其实就是子数组的最小长度啦)。要是没有这样的子数组,就返回-1哦。

🧠解题思路

  1. 我们先把leftright指针都放在数组开头,再设一个sum用来记录窗口里数的总和,初始值是0,还有一个minOp用来记录最小操作数,初始值设成一个很大的值,比如INT_MAX。🧐
  2. 接着,我们把right指针往右移,每移一次,就把新的数加到sum里。😜
  3. sum大于等于x的时候,我们就试着把left指针往右移,同时更新sum。在这个过程中,如果sum正好等于x,我们就比较一下当前窗口的长度(right - left + 1)和minOp,要是当前长度更小,就把minOp更新一下。😏
  4. 就这样一直重复步骤 2 和 3,直到right指针走到数组末尾。最后呢,如果minOp还是刚开始设的值,就说明没找到合适的子数组,返回-1;要是minOp变了,就把它返回。🎉

 🙋这个解题思路是怎么来的呢? 

 我们列出以下数组: 

 

 

💻代码实现(以 C++ 为例)

class Solution {
public:
    int minOperations(vector<int>& nums, int x) {
        // 获取数组nums的大小
        int n = nums.size();
        // 初始化滑动窗口的右指针、左指针以及用于累加数组元素总和的变量sum,初始值都设为0
        int right = 0, left = 0, sum = 0;

        // 遍历数组nums,将所有元素累加至sum中,得到数组元素的总和
        for (int a : nums) sum += a;

        // 计算目标值target,即数组所有元素之和减去给定的目标值x。
        // 其含义是,如果能在数组中找到一个子数组,其和等于target,
        // 那么通过删除该子数组两侧的元素,就能使剩余元素之和等于x。
        int target = sum - x;

        // 用于记录当前滑动窗口内元素的和,初始值设为0
        int tmp = 0;
        // 用于记录满足条件的子数组的最大长度(后续会根据此计算最少操作次数),
        // 初始值设为 -1,表示尚未找到满足条件的子数组
        int len = -1;

        // 如果计算出的目标值target小于0,说明无法通过删除元素使剩余元素之和等于x,直接返回 -1
        if (target < 0) return -1;

        // 开始滑动窗口操作,只要右指针right没有超出数组nums的范围,就持续循环
        while (right < n) {
            // 将当前右指针right指向的元素累加到tmp中,以更新当前窗口内元素的和
            tmp += nums[right];

            // 当tmp大于目标值target时,需要通过移动左指针left来缩小窗口,调整tmp的值
            while (tmp > target) {
                // 将左指针left指向的元素从tmp中减去,并将左指针left向右移动一位(先执行减法操作,再移动指针)
                tmp -= nums[left++];
            }

            // 如果经过上述调整后,tmp的值恰好等于目标值target,
            // 说明找到了一个满足条件的子数组,更新len为当前窗口长度(right - left + 1)和之前记录的len中的较大值
            if (tmp == target) len = max(len, right - left + 1);

            // 将右指针right向右移动一位,继续扩大窗口以探索后续元素
            right++;
        }

        // 如果len仍然为 -1,说明在整个数组中没有找到满足条件的子数组,即无法通过删除元素使剩余元素之和等于x,返回 -1
        if (len == -1) return -1;

        // 返回达到目标值x所需的最少操作次数,操作次数等于数组的总长度n减去满足条件的子数组的最大长度len
        return n - len;
    }
};

  📊复杂度分析

  • 时间复杂度 :先遍历数组计算总和得 $O(n)$,接着滑动窗口部分,虽内层循环情况较复杂,但整体主要由外层循环决定,所以时间复杂度大致为 $O(n)$,`n` 为数组 `nums` 长度。 
  • 空间复杂度: 仅用了几个常数级别的额外变量,空间复杂度为 $O(1)$

 


 

💯总结

✍通过这两道题,我们真的能感受到滑动窗口算法在处理数组问题的时候有多厉害!它就像一个超级聪明的小助手,把窗口维护得好好的,还能避开那些没用的计算,很快就能找到我们要的子结构呢。希望大家以后遇到类似的问题,都能熟练地用滑动窗口算法来解决哦,在算法的海洋里快乐地畅游!


🤗我会继续给大家带来更多好玩的算法知识哒,大家要持续关注我哦!😘

👉【A Charmer】 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/914151.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

重磅!通过国密局技术评审的112家密评机构公示

2024年10月28日&#xff0c;国家密码管理局官方网站发布《商用密码检测机构&#xff08;商用密码应用安全性评估业务&#xff09;资质申请通过技术评审的机构名单公示》&#xff0c;依据《商用密码管理条例》、《商用密码检测机构管理办法》有关规定&#xff0c;国家密码管理局…

【Windows】CMD命令学习——系统命令

CMD&#xff08;命令提示符&#xff09;是Windows操作系统中的一个命令行解释器&#xff0c;允许用户通过输入命令来执行各种系统操作。 系统命令 systeminfo - 显示计算机的详细配置信息。 tasklist - 显示当前正在运行的进程列表。 taskkill - 终止正在运行的进程。例如&am…

题目:Wangzyy的卡牌游戏

登录 - XYOJ 思路&#xff1a; 使用动态规划&#xff0c;设dp[n]表示当前数字之和模三等于0的组合数。 状态转移方程&#xff1a;因为是模三&#xff0c;所以和的可能就只有0、1、2。等号右边的f和dp都表示当前一轮模三等于k的组合数。以第一行为例&#xff1a;等号右边表示 j转…

会议直击|美格智能受邀出席第三届无锡智能网联汽车生态大会,共筑汽车产业新质生产力

11月10日&#xff0c;2024世界物联网博览会分论坛——第三届无锡智能网联汽车生态大会在无锡举行&#xff0c;美格智能CEO杜国彬受邀出席&#xff0c;并参与“中央域控&#xff1a;重塑汽车智能架构的未来”主题圆桌论坛讨论&#xff0c;与行业伙伴共同探讨智能网联汽车产业领域…

使用HTML、CSS和JavaScript创建动态雪人和雪花效果

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 ✨特色专栏&#xff1a…

【多线程奇妙屋】你听说过设计模式吗?软件开发中可全局访问一个对象的设计模式——单例模式,工作常用, 建议收藏 ! ! !

本篇会加入个人的所谓鱼式疯言 ❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言 而是理解过并总结出来通俗易懂的大白话, 小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的. &#x1f92d;&#x1f92d;&#x1f92d;可能说的不是那么严谨.但小编初心是能让更多人…

CTF记录

1. [SWPUCTF 2022 新生赛]android 用jadx打开&#xff0c;然后搜索NSS关键字 NSSCTF{a_simple_Android} 2. [SWPU 2024 新生引导]ez_SSTI 模板注入题目&#xff0c;直接焚靖可以秒了 填入数据 ls / 然后 cat /flag即可 获取成功 NSSCTF{2111e7ad-97c5-40d5-9a3b-a2f657bd45e8…

【C++滑动窗口 】2831. 找出最长等值子数组|1975

本文涉及的基础知识点 C算法&#xff1a;滑动窗口总结 本题其它解法 【C二分查找 滑动窗口】2831. 找出最长等值子数组|1975 LeetCode2831. 找出最长等值子数组 给你一个下标从 0 开始的整数数组 nums 和一个整数 k 。 如果子数组中所有元素都相等&#xff0c;则认为子数组…

《JVM第9课》垃圾回收器

先来看一张图&#xff0c;串行代表两个垃圾回收器按顺序执行&#xff0c;并行代表同时执行。STW代表工作线程暂停&#xff0c;Stop The World的意思。 垃圾回收器执行顺序执行方式作用区域使用算法说明Serial GC串行工作线程暂停&#xff0c;单线程进行垃圾回收新生代复制算法…

gitlab项目如何修改主分支main为master,以及可能遇到的问题

如果你希望将 Git 仓库的主分支名称从 main 修改为 master&#xff1a; 1. 本地修改分支名称 首先&#xff0c;切换到 main 分支&#xff1a; git checkout main将 main 分支重命名为 master&#xff1a; git branch -m main master2. 更新远程仓库 将本地更改推送到远程仓库…

【Keil5 使用Debug调试,阻塞在System_Init()中,并报错显示:no ‘read‘ permis】

计算机疑难杂症记录与分享006 Keil5 使用Debug调试&#xff0c;阻塞在System_Init()中&#xff0c;并报错显示error 65: access violation at 0x40021000 : no read permission1、问题背景2、问题原因3、问题解决3.1、解决方法1(亲测有效)&#xff1a;3.1.1、修改后的现象13.1.…

接口自动化测试实战(全网唯一)

&#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 接口自动化测试是指通过编写程序来模拟用户的行为&#xff0c;对接口进行自动化测试。Python是一种流行的编程语言&#xff0c;它在接口自动化测试中得到了广…

ubuntu 20.04 NVIDIA驱动、cuda、cuDNN安装

1. NVIDIA驱动 系统设置->软件和更新->附加驱动->选择NVIDIA驱动->应用更改。该界面会自动根据电脑上的GPU显示推荐的NVIDIA显卡驱动。 运行nvidia-smi: NVIDIA-SMI has failed because it couldnt communicate with the NVIDIA driver. Make sure that the lat…

HarmonyOS开发 API 13发布首个Beta版本,解决了哪些问题?

HarmonyOS 5.0.1 Beta3&#xff0c;是HarmonyOS开发套件基于API 13正式发布的首个Beta版本。该版本在OS能力上主要增强了C API的相关能力&#xff0c;多个特性补充了C API供开发者使用。HarmonyOS 5.0.1 Beta3完整配套信息如下&#xff1a; 已解决的问题 DevEco Studio 5.0.…

SQL,力扣题目1194,锦标赛优胜者

一、力扣链接 LeetCode1194 二、题目描述 Players 玩家表 -------------------- | Column Name | Type | -------------------- | player_id | int | | group_id | int | -------------------- player_id 是此表的主键(具有唯一值的列)。 此表的每一行表示每个玩…

计算机毕业设计Python+图神经网络考研院校推荐系统 考研分数线预测 考研推荐系统 考研爬虫 考研大数据 Hadoop 大数据毕设 机器学习 深度学习

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

virtualBox部署minikube+istio

环境准备 virtualBox安装 直接官网下载后安装即可&#xff0c;网上也有详细教程。镜像使用的centos7。 链接&#xff08;不保证还可用&#xff09;&#xff1a;http://big.dxiazaicc.com/bigfile/100/virtualbox_v6.1.26_downcc.com.zip?auth_key1730185635-pWBtV8LynsxPD0-0-…

一文了解Android本地广播

在 Android 开发中&#xff0c;本地广播&#xff08;Local Broadcast&#xff09;是一种轻量级的通信机制&#xff0c;主要用于在同一应用进程内的不同组件之间传递消息&#xff0c;而无需通过系统的全局广播机制。这种方法既可以提高安全性&#xff08;因为广播仅在应用内传播…

CoD-MIL: 基于诊断链提示的多实例学习用于全切片图像分类|文献速递-基于深度学习的病灶分割与数据超分辨率

Title 题目 CoD-MIL: Chain-of-Diagnosis Prompting Multiple Instance Learning for Whole Slide Image Classification CoD-MIL: 基于诊断链提示的多实例学习用于全切片图像分类 01 文献速递介绍 病理检查被广泛视为肿瘤诊断的金标准&#xff0c;因为它为治疗决策和患者…