C++算法——滑动窗口

news2024/11/24 22:33:17

一、长度最小的子数组

1.链接

209. 长度最小的子数组 - 力扣(LeetCode)

2.描述

3.思路

本题从暴力求解的方式去切入,逐步优化成“滑动窗口”,首先,暴力枚举出各种组合的话,我们先让一个指针指向第一个,然后往后逐一遍历区间,也就是穷举出所有的子数组,但根据题目要求,当我们穷举出大于或者等于target的区间时,右边指针再向后遍历穷举的结果将没有意义,所以不需要再去往后走,而是进行下一轮遍历(前提是本题中数据全是正整数),当左指针往后走一步后,穷举的思路需要我们从头再走一次重复的数据,此时我们对其进行优化,定义一个sum值去记录区间数据,就可以不需要再次遍历一次,经过优化后,我们会发现,解题思路就变成了:

定义两个左右指针,一起从头往前走,并且记录两个指针区间的和sum,right指针往后,当大于等于目标值时,则停下记录长度,然后left走一步,进行判断是否仍然满足大于等于目标值,若是满足则让left继续走,当长度出现比原先短的区间时,进行更新最小区间的长度,left走到小于目标值时,让right进行往前走,直到right遍历完一遍数组,这种两个指针同向一起走的思路叫做“滑动窗口”

4.参考代码

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) 
    {
        int left = 0;
        int right = 0;
        int sum = nums[0];
        int len = 0;
        while(right < nums.size())
        {
            if(sum < target)
            {
                ++right;
                if(right < nums.size())
                    sum+=nums[right];
            }
            else
            {
                len = len == 0 ? right-left+1 :  min(len,right - left + 1);
                if(len == 1) break;
                sum-=nums[left++];
            }
        }
        return len;
    }
};

二、无重复字符的最长子串

1.链接

3. 无重复字符的最长子串 - 力扣(LeetCode)

2.描述

3.思路

由于是对子串进行判断,子串是一段连续的区间,所以我们可以尝试采用滑动窗口的思路解决

满足窗口滑动的条件就是:判断窗口内是否有重复字符,可以利用哈希表去进行统计

当没有重复时则right往前走,当有重复时则left往前,这个过程中记录下最长的子串

4.参考代码

class Solution 
{
public:
    int lengthOfLongestSubstring(string s) 
    {
        if(s.size() == 0)
        {
            return 0;
        }
        int left = 0;
        int right = 0;
        int len = 0;
        set<char> hash;
        while(right < s.size())
        {
            if((hash.insert(s[right])).second)//插入成功意味着没有重复
            {
                right++;
                len = max(len,right-left);
            }
            else//出现重复
            {
                hash.erase(s[left++]);
            }
        }
        return len;
    }
};

三、最大连续1的个数|||

1.链接

1004. 最大连续1的个数 III - 力扣(LeetCode)

2.描述

3.思路

可以将题意转化为,在一段区间内,0的数量不能超过k个,利用滑动窗口去解决

当超过k个时,left往前走,直到将最前面的0给退出窗口,没有超过时,则right往前走,不断扩大窗口,过程中记录下窗口长度最大的值

4.参考代码

class Solution {
public:
    int longestOnes(vector<int>& nums, int k) 
    {
        int left = 0;
        int right= 0;
        int n = nums.size();
        int len = 0;
        while(right < n)
        {
            while(right < n && (k != 0 || nums[right] == 1))
            {
                if(nums[right] == 0)
                {
                    k--;
                }
                right++;
                len = max(len,right-left);
            }
            while(left < n && k == 0)
            {
                if(nums[left++] == 0)
                    k++;
            }
        }
        return len;
    }
};

四、将x减到0的最小操作数

1.链接

1658. 将 x 减到 0 的最小操作数 - 力扣(LeetCode)

2.描述

3.思路

我们可以先将问题转换成,在数组内找到一段最长连续的子区间之和会刚好等于数组之和减去x的值

将问题变成在数组中找一段最长的连续子区间之和等于目标值的问题后,我们就可以使用滑动窗口的思路去解决,思路可以参考第一题“长度最小的子数组”

4.参考代码

class Solution 
{
public:
    int minOperations(vector<int>& nums, int x) 
    {
        int n = nums.size();
        int sum = 0;
        for(auto n:nums)
        {
            sum+=n;
        }
        int target = sum - x;
        if(target < 0) return -1;
        //找到最长的子区间
        int len = -1;
        for(int left = 0,right = 0,s = 0; right < n;right++ )
        {
            s += nums[right];//进窗口
            while(s > target)//出窗口
            {
                s-=nums[left++];
            }
            if(s == target)
            {
                len = max(len,right-left+1);
            }
        }
    
        return len == -1 ? len : n-len;
    }
};

五、水果成篮

1.链接

904. 水果成篮 - 力扣(LeetCode)

2.描述

3.思路

根据题意,利用滑动窗口的思路,当窗口内的水果种类超过两种时则开始出窗口,过程中记录下窗口的长度,利用哈希表去进行统计

4.参考代码

class Solution {
public:
    int totalFruit(vector<int>& fruits) 
    {
        map<int,int> hash;
        int ret = 0;
        for(int left = 0,right = 0;right<fruits.size();right++)
        {
            hash[fruits[right]]++;
            while(hash.size()>2)
            {
                hash[fruits[left]]--;
                if(hash[fruits[left]] == 0)
                {
                    hash.erase(fruits[left]);
                }
                left++;
            }
            ret = max(ret,right-left+1);
        }
        return ret;
    }
};

六、找到字符串中所有字母异位词

1.链接

438. 找到字符串中所有字母异位词 - 力扣(LeetCode)

2.描述

3.思路

4.参考代码

class Solution 
{
public:
    vector<int> findAnagrams(string s, string p) 
    {
        int hash1[26] = {0};
        int hash2[26] = {0};
        for(auto c:p)
        {
            hash1[c-'a']++;
        }
        int m = p.size();
        vector<int> ret;
        for(int left = 0,right = 0,count = 0; right < s.size(); right++)
        {
            char in = s[right];
            hash2[in - 'a']++;//入窗口
            if(hash2[in - 'a'] <= hash1[in - 'a']) count++;//维护count
            char out = s[left];
            if(right-left+1 > m)//出窗口
            {
                if(hash2[out - 'a'] <= hash1[out - 'a']) count--;//维护count
                hash2[out - 'a']--;
                left++;
            }
            //判断目标
            if(count == m)
            {
                ret.push_back(left);
            }
        }
        return ret;
    }
};

七、串联所有单词的子串

1.链接

30. 串联所有单词的子串 - 力扣(LeetCode)

2.描述

3.思路

4.参考代码

class Solution {
public:
    vector<int> findSubstring(string s, vector<string>& words) 
    {
        int len = words[0].size();
        unordered_map<string,int> m1;
        unordered_map<string,int> m2;
        vector<int> ret;
        for(auto& s:words) m1[s]++;
        for(int i = 0;i<len;i++)//以i位置为起点
        {
            for(int left = i,right = i+len-1,count = 0; right < s.size() ; right+=len)//滑动窗口
            {
                string in = s.substr(right-len+1,len);
                m2[in]++;//入窗口
                if(m2[in] <= m1[in]) count++;//维护count
                if(right-left+1 > len*words.size())//出窗口
                {
                    string out = s.substr(left,len);
                    if(m2[out] <= m1[out]) count--;
                    m2[out]--;
                    left+=len;
                }
                if(count == words.size()) ret.push_back(left);
            }
            m2.clear();
        }
        return ret;
    }
};

八、最小覆盖子串

1.链接

76. 最小覆盖子串 - 力扣(LeetCode)

2.描述

3.思路

有了前面的经验,不难想到这题该怎么用滑动窗口解决,根据题意分析,我们知道首先将t内的字符记录到哈希表hash1中,然后让滑动窗口的右侧不断的往前走,直到满足题目条件,即滑动窗口内的字符串包含了t内的字符,此时让left往前收缩,记录下最小的区间,然后直到不再满足条件后,让right继续往后找满足条件的子串,最终记录下最短的那个子串即可,当然,还有如何优化哈希比较的细节需要注意,以及对于如何记录下最短子串的考量

4.参考代码

class Solution {
public:
    string minWindow(string s, string t) 
    {
        int n = s.size();
        int hash1[128] = {0};
        int hash2[128] = {0};
        for(auto& c : t)  hash1[c]++;
        int begin = -1; int len = s.size()+1;
        for(int left = 0,right = 0,count = 0;right < n;right++)
        {
            char in = s[right];
            hash2[in]++;
            if(hash2[in] <= hash1[in]) count++;
            while(count == t.size())
            {
                if(right-left+1 < len)
                {
                    len = right-left+1;
                    begin = left;
                }
                char out = s[left++];
                if(hash2[out] <= hash1[out]) count--;
                hash2[out]--;
            }
        }
        if(begin == -1) return "";
        else return s.substr(begin,len);
    }
};

总结

本章节主要整理了关于滑动窗口的算法思想,由简单到困难逐步递进,整理了八道相关例题以及思路解析提供参考,也可以通过链接去做

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

手机销量分析案例

项目背景 某电商商城随着业务量的发展&#xff0c;积累了大量的用户手机销售订单数据。决策层希望能够通过对这些数据的分析了解更多的用户信息及用户的分布&#xff0c;从而可以指导下一年的市场营销方案以及更加精准的定位市场&#xff0c;进行广告投放。 数据说明 数据时…

JAVA基础02-Java语言基础以及编译准备工作

什么是JAVA语言 Java是一门面向对象的编程语言&#xff0c;不仅吸收了C语言的各种优点&#xff0c;还摒弃了C里难以理解的多继承、指针等概念&#xff0c;因此Java语言具有功能强大和简单易用的两个特征。 &#xff08;可以编写桌面应用程序、Web应用程序、分布式系统和嵌入式…

洛谷P1000超级玛丽游戏题解[Python, Rust, Go]

题目 打印超级玛丽字符图像 小技巧 直接复制题目的超级玛丽符号首行会有空格问题&#xff0c;一直AC不过&#xff0c;一行一行地复制就OK了&#x1f44c;。 Rust 题解 fn main() {println!(" ********************####....#.#..###.....##....###...…

什么是 Nginx?(一)

前段时间在网上看到一个有意思的话题&#xff1a;只知道 Nginx 牛逼&#xff0c;却不知道它怎么支持百万并发&#xff1f; 无论是运维、开发、测试&#xff0c;Nginx 技术栈的学习总是必不可少的&#xff0c;只是不同的岗位掌握的深度与广度不同而已。 Nginx 是开源、高性能、…

MATLAB科研绘图与学术图表绘制从入门到精通

&#x1f482; 个人网站:【 摸鱼游戏】【神级代码资源网站】【工具大全】&#x1f91f; 一站式轻松构建小程序、Web网站、移动应用&#xff1a;&#x1f449;注册地址&#x1f91f; 基于Web端打造的&#xff1a;&#x1f449;轻量化工具创作平台&#x1f485; 想寻找共同学习交…

算法学习——LeetCode力扣图论篇1(797. 所有可能的路径、200. 岛屿数量、695. 岛屿的最大面积)

算法学习——LeetCode力扣图论篇1 797. 所有可能的路径 797. 所有可能的路径 - 力扣&#xff08;LeetCode&#xff09; 描述 给你一个有 n 个节点的 有向无环图&#xff08;DAG&#xff09;&#xff0c;请你找出所有从节点 0 到节点 n-1 的路径并输出&#xff08;不要求按特…

golang语言系列:Web框架+路由 之 Gin

云原生学习路线导航页&#xff08;持续更新中&#xff09; 本文是golang语言学习系列&#xff0c;本篇对Gin框架的基本使用方法进行学习 1.Gin框架是什么 Gin 是一个 Go (Golang) 编写的轻量级 http web 框架&#xff0c;运行速度非常快&#xff0c;如果你是性能和高效的追求者…

java项目基于Springboot和Vue的高校心理教育辅导系统的设计与实现

今天要和大家聊的是基于Springboot和Vue的高校心理教育辅导系统的设计与实现 &#xff01;&#xff01;&#xff01; 有需要的小伙伴可以通过文章末尾名片咨询我哦&#xff01;&#xff01;&#xff01; &#x1f495;&#x1f495;作者&#xff1a;李同学 &#x1f495;&…

C++完美转发(适合小白)

我们知道&#xff0c;C中有左值引用和右值引用&#xff0c;首先我们要知道什么是左值什么是右值。 左值&#xff1a;表达式结束后依然存在的持久对象。左值可以出现在赋值语句的左边或右边。例如&#xff0c;变量和函数返回的引用都是左值。左值通常有持久的地址&#xff0c;可…

Python深度学习034:cuda的环境如何配置

文章目录 1.安装nvidia cuda驱动CMD中看一下cuda版本:下载并安装cuda驱动2.创建虚拟环境并安装pytorch的torch_cuda3.测试附录1.安装nvidia cuda驱动 CMD中看一下cuda版本: 注意: 红框的cuda版本,是你的显卡能装的最高的cuda版本,所以可以选择低于它的版本。比如我的是11…

Go项目结构整洁实现|GitHub 3.5k

一、前言 hi&#xff0c;大家好&#xff0c;这里是白泽。今天给大家分享一个GitHub &#x1f31f; 3.5k 的 Go项目&#xff1a;go-backend-clean-arch https://github.com/amitshekhariitbhu/go-backend-clean-architecture 这个项目是一位老外写的&#xff0c;通过一个 HTT…

HTML基本元素

文章目录 如何制作标题如何制作文字如何做粗体字检查我们程序码给输出文字添加属性 HTML 一个HTML标签包含着&#xff1a; 起始标签&#xff1a;它包含了元素的名字&#xff0c;夹在一对 <、>&#xff08;尖括号&#xff09;之间。它指明元素从何处开始生效。结束标签&am…

《Git版本控制管理》笔记

第三章 git --version查看版本号git --help查看帮助文档裸双破折号分离参数 git diff -w master origin – tools/Makefile将当前目录或任何目录转化为Git版本库 git init 初始化之后项目目录中&#xff0c;有名为.git的文件git status 查看git状态git commit 提供日志消息和作…

整型之韵,数之舞:大小端与浮点数的内存之旅

✨✨欢迎&#x1f44d;&#x1f44d;点赞☕️☕️收藏✍✍评论 个人主页&#xff1a;秋邱’博客 所属栏目&#xff1a;人工智能 &#xff08;感谢您的光临&#xff0c;您的光临蓬荜生辉&#xff09; 1.0 整形提升 我们先来看看代码。 int main() {char a 3;char b 127;char …

Java基础核心Map

在Java中&#xff0c;Map是一种用于存储键值对&#xff08;key-value pairs&#xff09;的集合类型。它提供了一种将键映射到值的方式&#xff0c;其中每个键在Map中都是唯一的。Map接口是java.util包中的一部分。 常用实现类&#xff1a; HashMap: 基于哈希表实现的Map&#…

java中split(“.“)失效问题

来源&#xff1a;比较版本号_牛客题霸_牛客网 在写到这道算法题的时候&#xff0c;发现一个问题&#xff0c; String[] leftversion1.split("."); 返回结果为空&#xff0c;经过查阅得知&#xff0c;是split中的正则表达式里的问题&#xff0c;这个 . 代表的意思是…

KIMI官方精选提示词,好牛的感觉啊啊啊!

晚上好&#xff0c;我是云桃桃。一个希望帮助更多朋友快速入门 WEB 前端的程序媛。 云桃桃 1枚程序媛&#xff0c;大专生&#xff0c;2年时间从1800到月入过万&#xff0c;工作5年买房。 分享成长心得。 255篇原创内容-公众号 后台回复“前端工具”可获取开发工具&#xff0…

图论- 最小生成树

一、最小生成树-prim算法 1.1 最小生成树概念 一幅图可以有很多不同的生成树&#xff0c;比如下面这幅图&#xff0c;红色的边就组成了两棵不同的生成树&#xff1a; 对于加权图&#xff0c;每条边都有权重&#xff08;用最小生成树算法的现实场景中&#xff0c;图的边权重…

使用Vue实现CSS过渡和动画

01-初识动画和过渡 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>使用vue实现css过渡和动画&l…

Ethernet修改网卡名称

如何修改Ethernet网卡名称 kernel/common/net/core/dev.c ---------------------------------------------------------------------- 8849/** 8850 * register_netdev - register a network device 8851 * @dev: device to register 8852 * 8853 * Take a completed network d…