C++ 优先算法 —— 无重复字符的最长子串(滑动窗口)

目录

题目: 无重复字符的最长子串

1. 题目解析

2. 算法原理

Ⅰ. 暴力枚举

Ⅱ. 滑动窗口(同向双指针)

3. 代码实现

Ⅰ. 暴力枚举

Ⅱ. 滑动窗口


题目: 无重复字符的最长子串

1. 题目解析

题目截图:

此题所说的子串与长度最小的子数组题目中所说的子数组相当于一个概念,都是数组中连续的一段,区别在于子串是在一个字符串中,子数组是在一个整数数组中。

 题目中要求找到一个没有重复字符的子串,并返回它的长度。

所以看到这里有三个长度为3的子串且是最长的,所以返回3。

这里可以看出全是b,只能找到一个字符,并返回长度1,因为再往后扩展也是重复的了。

 所以,这道题的要求,并要求返回什么如上面所示。

2. 算法原理

这道题也有两种解法的:

  1. 暴力枚举
  2. 滑动窗口 

Ⅰ. 暴力枚举

暴力枚举也就是把所有子串都枚举出来,枚举子串的时候,以某一个位置为起点,然后向后枚举,再接着以另一个某一个位置为起点,再向后枚举,这里注意的是枚举并不是全部枚举,而是当枚举一个位置时,继续再向后枚举的时候,如果发现有重复的字符出现,那么就停止枚举,也就是说,以这个位置开头的只能枚举到这里了,然后统计长度,接下来才是枚举第二个开头的,一直把所有情况枚举到,最后找一个长度的最大值。 

这里的长度为2。 

这里长度为3,通过上面题目解析中已经得知这里最长长度就是3. 

固定每一个有可能的起始位置,然后依次向后扩展,直到扩展不能扩展为止,然后统计一下长度,把所有情况都枚举到,再统计一下最大值。
 

不过这里我们都是通过肉眼观察它们是否有重复的,但是程序中可不会直接就能观测到,这里就需要处理是否重复的细节问题了,可以借助开放定址法的hash表来解决重复问题,只需要把对应的字母映射到表上(遍历一个字符就让它映射到哈希表上),然后表里字母对应位置的数据统计它出现的次数,若是大于 1,那么它就重复。

所以这里的解法:暴力枚举+哈希表(表的数据存储的是字符出现的次数,为了判断字符是否重复出现)

这里时间复杂度:O(N²)。 

所以,暴力枚举:

 先判断 right 指向的字符在不在 hash表 里(也就是看表里对应的数据是不是大于 0),不在就放进去,然后 right 向后移动,再接着判断 right 指向的元素在不在,不在就放进去,right 再向后移动,重复上面的操作(不在就在表里对应的位置 +1,然后 right 后移)

再接着判断重复上面操作: 

判断不在,重复上面操作: 

此时判断不在,重复上面操作,这时right指向了第二个字符a:

当上面right 到 a 时,字符先前已经存在于哈希表里了,这时候就要停止枚举操作,"deabc"的长度就是以d开头的能得到无重复字符串的子串的最长长度。

接下来,让left换一个位置,left后移动一位,此时再让right回退至left的位置:

接下来继续重复上面的操作,直到把所有符合条件的情况枚举出来,统计长度,再获取最长的那个长度返回即可。 

Ⅱ. 滑动窗口(同向双指针)

在上面暴力枚举种,我们发现有些情况是可以优化的,我们发现如下的情况:

这时left再往下一个移动的时候,这时到了字符a,让right回退到left,再继续枚举发现还是会到同一个a位置停止枚举,当left跳过了第一个出现的字符a之后,停止枚举的位置就发生变化了:

也就是说:

并且这里发现,在这个区间内依次往后枚举起始位置的话,因为终点是同样的,这时子串的长度就会递减,因此就可以让right不要拐回去了,让right在该位置先不动,先调整left,让left跳过有重复的字符:

暴力解法中,left移动到新的位置的时候,right就要回退至left的同位置,但这里也可以有个优化,也就是left跳过重复字符后,right是没有必要回退至left的:

 因此,我们发现这里left和right的移动方向是一致的,也就是同向双指针:

这里的窗口就是left和right区间内维护的无重复字符的子串,让字符先进入窗口,然后判断,当有重复的字符的时候就让它出窗口:

 这里的解法就是:利用规律,使用滑动窗口来解决问题。

注意:上面的情况每次都要更新结果,结果就是字符串的子串的长度。

规律:

  1. 当里面有重复的字符的时候,让left先向右移动,把出现的重复字符的位置之前的字符给跳过(因为它们的最后终点都会为这个重复的字符的第二次出现的位置)。
  2. 当left到符合要求的位置时候,right是不用回退的,可以继续向后移动,扩展该区间。

所以这里就可以同上一道题 长度最小的子数组 用滑动窗口的方法步骤解决:

  1. 先定义 left 和 right 并都初始化为0,充当窗口的左右端点。
  2. 进窗口(这里让字符串进入哈希表即可)。
  3. 判断:当窗口里有重复的字符时候,就要出窗口(就是从哈希表中删除该字符,注意:在删除之后,要再继续判断,直到没有重复字符为止)。
  4. 进出窗口都需要更新结果(符合要求的子串的长度,取新旧结果中最大的那一个即可)。
  5. 直到right指向最右边为止就就结束了。

 这里时间复杂度情况也同于  长度最小的子数组 的情况,根据实际情况是每一步操作仅仅会让 right 向右移动 1 位或 left 向右移动 1 位,直到 right 移动到最后的位置。最坏的情况就是两个指针都遍历了一遍该数组,也就是2n次,所以时间复杂度为:O(N)。

接下来实现两种方法的代码:

3. 代码实现

题目链接:无重复字符的最长子串

Ⅰ. 暴力枚举

时间复杂度:O(N²)。

//暴力枚举
class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int n = s.size();
        int len = 0;
        for(int left = 0; left < n; left++)  //先固定起始位置
        {
            int hash[128] = {0};  //将字符串中的字符出现次数映射到hash表
            for(int right = left; right < n; right++)
            //依次从left位置向后枚举扩展区间
            {
                hash[s[right]]++;
                //让字符充当下标,该位置字符出现,就让它对应的hash值+1
                if(hash[s[right]] > 1)  //大于1说明出现重复字符了
                {
                    break;      //直接退出循环
                }
                len = max(len, right - left + 1);   //更新结果
            }
        }
        return len;
    }
};

提交记录:

Ⅱ. 滑动窗口

时间复杂度:O(N)。

//滑动窗口
class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int n = s.size();
        int len = 0;
        int hash[128] = { 0 };   //使用数组模拟hash表
        //遇到重复的不需要让right回退了,让left跳过重复的字符之后,再处理right即可
        for(int left = 0, right = 0; right < n; right++)  
        {
            hash[s[right]]++;  //进入窗口

            while(hash[s[right]]>1) //判断
            {
                //大于1说明出现重复了
                hash[s[left++]]--;    //出窗口
            }
            len = max(len,right-left+1);  //更新结果         
        }
        return len;
    }
};

提交记录:

制作不易,若有不足之处或出问题的地方,请各位大佬多多指教 ,感谢大家的阅读支持!!!   

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

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

相关文章

easyui combobox 只能选择第一个问题解决

easyui combobox 只能选择第一个问题解决 问题现象 在拆分开票的时候&#xff0c;弹出框上面有一个下拉框用于选择需要新增的明细行&#xff0c;但是每次只能选择到第一个 选择第二条数据的时候默认选择到第一个了 代码如下 /*新增发票编辑窗口*/function addTicketDialog…

机器学习周志华学习笔记-第6章<支持向量机>

机器学习周志华学习笔记-第6章<支持向量机> 卷王&#xff0c;请看目录 6支持向量机6.1 函数间隔与几何间隔6.1.1 函数间隔6.1.2 几何间隔 6.2 最大间隔与支持向量6.3 对偶问题6.4 核函数6.5 软间隔支持向量机6.6 支持向量机6.7核方法 6支持向量机 支持向量机是一种经典…

111. UE5 GAS RPG 实现角色技能和场景状态保存到存档

实现角色的技能存档保存和加载 首先&#xff0c;我们在LoadScreenSaveGame.h文件里&#xff0c;增加一个结构体&#xff0c;用于存储技能相关的所有信息 //存储技能的相关信息结构体 USTRUCT(BlueprintType) struct FSavedAbility {GENERATED_BODY()//需要存储的技能UPROPERT…

ArcGIS pro中的回归分析浅析(加更)关于广义线性回归工具的补充内容

在回归分析浅析中篇的文章中&#xff0c; 有人问了一个问题&#xff1a; 案例里的calls数据貌似离散&#xff0c;更符合泊松模型&#xff0c;为啥不采用泊松而采用高斯呢&#xff1f; 确实&#xff0c;在中篇中写道&#xff1a; 在这个例子中我们为了更好地解释变量&#x…

从 HTML 到 CSS:开启网页样式之旅(二)—— 深入探索 CSS 选择器的奥秘

从 HTML 到 CSS&#xff1a;开启网页样式之旅&#xff08;二&#xff09;—— 深入探索 CSS 选择器的奥秘 前言一、CSS基本选择器1. 通配选择器2. 元素选择器3. 类选择器4. id选择器5.基本选择器总结 二、CSS复合选择器1. 后代选择器2. 子选择器3. 相邻兄弟选择器4.交集选择器5…

【机器学习chp7】SVM

参考1&#xff0c;笔记 SVM笔记.pdf 参考2&#xff1a;王木头视频 什么是SVM&#xff0c;如何理解软间隔&#xff1f;什么是合叶损失函数、铰链损失函数&#xff1f;SVM与感知机横向对比&#xff0c;挖掘机器学习本质_哔哩哔哩_bilibili 目录 一、SVM模型 二、构建决策函…

【C++】读取数量不定的输入数据

读取数量不定的输入数据 似乎是一个很实用的东西&#xff1f; 问题&#xff1a; 我们如何对用户输入的一组数&#xff08;事先不知道具体有多少个数&#xff09;求和&#xff1f; 这需要不断读取数据直至没有新的输入为止。&#xff08;所以我们的代码就是这样设计的&#x…

HarmonyOS4+NEXT星河版入门与项目实战(20)------状态管理@ObjectLink @Observed

文章目录 1、用法图解2、案例实现1、任务类改造2、参数改造变量3、完整代码4、运行效果4、总结1、用法图解 2、案例实现 上一节的案例中,一直有一个功能没有生效,就是任务完成后对应的任务行变灰,任务字体出现中划线删除的效果。而该功能一直不生效的原因就是要改变的数据值…

2024年工信部大数据分析师证书报考条件是怎样的?有什么用

大数据分析师&#xff0c;乃是这样一类专业人才&#xff0c;他们凭借着先进且高效的数据分析技术以及各类实用工具&#xff0c;对规模庞大、纷繁复杂的海量数据展开全面而细致的清洗、处理、分析以及解读工作。其工作的核心目标在于为企业的决策制定提供有力依据&#xff0c;推…

基于vite创建的react18项目的单元测试

题外话 最近一个小伙伴进了字节外包&#xff0c;第一个活就是让他写一个单元测试。 嗯&#xff0c;说实话&#xff0c;在今天之前我只知道一些理论&#xff0c;但是并没有实操过&#xff0c;于是我就试验了一下。 通过查询资料&#xff0c;大拿们基本都说基于vite的项目&…

探秘嵌入式位运算:基础与高级技巧

目录 一、位运算基础知识 1.1. 位运算符 1.1.1. 与运算&#xff08;&&#xff09; 1.1.2. 或运算&#xff08;|&#xff09; 1.1.3. 异或运算&#xff08;^&#xff09; 1.1.4. 取反运算&#xff08;~&#xff09; 1.1.5. 双重按位取反运算符&#xff08;~~&#xf…

SpringBoot - 优雅的实现【账号登录错误次数的限制和锁定】

文章目录 Pre需求实现步骤简易实现1. 添加依赖2. 配置文件3. 自定义注解4. AOP切面5. 使用自定义注解&#xff1a;6. 测试 附总结 Pre SpringBoot - 优雅的实现【流控】 需求 需求描述&#xff1a; 登录错误次数限制&#xff1a;在用户登录时&#xff0c;记录每个账号的登录错…

SRIO DRP动态速率配置说明(详细讲解)

目录 一、SRIO IP时钟结构 1、时钟内部结构 2、时钟直接的关系 3、时钟计算原理 ​二、SRIO DRP介绍 ​1、MMCM DRP配置(xapp888) 2、CPLL DRP配置(ug476) 关于CPLL DRP配置详细介绍&#xff1a; GTX中CPLL、QPLL DRP动态配置方法&#xff08;详解&#xff09;-CSDN博客…

动态规划之背包问题

0/1背包问题 1.二维数组解法 题目描述&#xff1a;有一个容量为m的背包&#xff0c;还有n个物品&#xff0c;他们的重量分别为w1、w2、w3.....wn&#xff0c;他们的价值分别为v1、v2、v3......vn。每个物品只能使用一次&#xff0c;求可以放进背包物品的最大价值。 输入样例…

推荐一款龙迅HDMI2.0转LVDS芯片 LT6211UX LT6211UXC

龙迅的HDMI2.0转LVDS芯片LT6211UX和LT6211UXC是两款高性能的转换器芯片&#xff0c;它们在功能和应用上有所差异&#xff0c;同时也存在一些共同点。以下是对这两款芯片的详细比较和分析&#xff1a; 一、LT6211UX 主要特性&#xff1a; HDMI2.0至LVDS和MIPI转换器。HDMI2.0输…

深度学习模型:循环神经网络(RNN)

一、引言 在深度学习的浩瀚海洋里&#xff0c;循环神经网络&#xff08;RNN&#xff09;宛如一颗独特的明珠&#xff0c;专门用于剖析序列数据&#xff0c;如文本、语音、时间序列等。无论是预测股票走势&#xff0c;还是理解自然语言&#xff0c;RNN 都发挥着举足轻重的作用。…

[STM32]从零开始的STM32 FreeRTOS移植教程

一、前言 如果能看到这个教程的话&#xff0c;说明大家已经学习嵌入式有一段时间了。还记得嵌入式在大多数时候指的是什么吗&#xff1f;是的&#xff0c;我们所说的学习嵌入式大部分时候都是在学习嵌入式操作系统。从简单的一些任务状态机再到复杂一些的RTOS&#xff0c;再到最…

《操作系统 - 清华大学》5 -4:虚拟技术

文章目录 0. 虚拟存储的定义1. 目标2.局部性原理3. 虚拟存储的思路与规则4. 虚拟存储的基本特征5. 虚拟页式存储管理5.1 页表表项5.2 示例 0. 虚拟存储的定义 1. 目标 虚拟内存管理技术&#xff0c;简称虚存技术。那为什么要虚存技术&#xff1f;在于前面覆盖和交换技术&#…

2024APMCM亚太杯数学建模C题【宠物行业】原创论文分享

大家好呀&#xff0c;从发布赛题一直到现在&#xff0c;总算完成了2024 年APMCM亚太地区大学生数学建模竞赛C题的成品论文。 给大家看一下目录吧&#xff1a; 目录 摘 要&#xff1a; 10 一、问题重述 14 二&#xff0e;问题分析 15 2.1问题一 15 2.2问题二 15 2.3问题三…

YOLOv8模型pytorch格式转为onnx格式

一、YOLOv8的Pytorch网络结构 model DetectionModel((model): Sequential((0): Conv((conv): Conv2d(3, 64, kernel_size(3, 3), stride(2, 2), padding(1, 1))(act): SiLU(inplaceTrue))(1): Conv((conv): Conv2d(64, 128, kernel_size(3, 3), stride(2, 2), padding(1, 1))(a…