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

news2024/11/27 14:54:41

目录

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

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;
    }
};

提交记录:

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

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

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

相关文章

[网安靶场] [更新中] UPLOAD LABS —— 靶场笔记合集

GitHub - c0ny1/upload-labs: 一个想帮你总结所有类型的上传漏洞的靶场一个想帮你总结所有类型的上传漏洞的靶场. Contribute to c0ny1/upload-labs development by creating an account on GitHub.https://github.com/c0ny1/upload-labs 0x01&#xff1a;UPLOAD LABS 靶场初识…

安装python拓展库pyquery相关问题

我采用的是离线whl文件安装, 从官方库地址: https://pypi.org/, 下载whl文件, 然后在本地电脑上执行pip install whl路径文件名.whl 但是在运行时报错如下图 大体看了看, 先是说了说找到了合适的 lxml>2.1, 在我的python库路径中, 然后我去看了看我的lxml版本, 是4.8.0, 对…

春秋云境 CVE 复现

CVE-2022-4230 靶标介绍 WP Statistics WordPress 插件13.2.9之前的版本不会转义参数&#xff0c;这可能允许经过身份验证的用户执行 SQL 注入攻击。默认情况下&#xff0c;具有管理选项功能 (admin) 的用户可以使用受影响的功能&#xff0c;但是该插件有一个设置允许低权限用…

图论入门编程

卡码网刷题链接&#xff1a;98. 所有可达路径 一、题目简述 二、编程demo 方法①邻接矩阵 from collections import defaultdict #简历邻接矩阵 def build_graph(): n, m map(int,input().split()) graph [[0 for _ in range(n1)] for _ in range(n1)]for _ in range(m): …

Jackson库中JsonInclude的使用

简介 JsonInclude是 Jackson 库&#xff08;Java 中用于处理 JSON 数据的流行库&#xff09;中的一个注解。它用于控制在序列化 Java 对象为 JSON 时&#xff0c;哪些属性应该被包含在 JSON 输出中。这个注解提供了多种策略来决定属性的包含与否&#xff0c;帮助减少不必要的数…

鸿蒙学习自由流转与分布式运行环境-价值与架构定义(1)

文章目录 价值与架构定义1、价值2、架构定义 随着个人设备数量越来越多&#xff0c;跨多个设备间的交互将成为常态。基于传统 OS 开发跨设备交互的应用程序时&#xff0c;需要解决设备发现、设备认证、设备连接、数据同步等技术难题&#xff0c;不但开发成本高&#xff0c;还存…

【论文复现】融入模糊规则的宽度神经网络结构

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀ 融入模糊规则的宽度神经网络结构 论文概述创新点及贡献 算法流程讲解核心代码复现main.py文件FBLS.py文件 使用方法测试结果示例&#xff1a…

网上蛋糕售卖店管理系(Java+SpringBoot+MySQL)

摘 要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;在计算机上安装网上蛋糕售卖店管理系统软件来发挥其高效地信息处理的作用…

Vue.js基础——贼简单易懂!!(响应式 ref 和 reactive、v-on、v-show 和 v-if、v-for、v-bind)

Vue.js是一个渐进式JavaScript框架&#xff0c;用于构建用户界面。它专门设计用于Web应用程序&#xff0c;并专注于视图层。Vue允许开发人员创建可重用的组件&#xff0c;并轻松管理状态和数据绑定。它还提供了一个虚拟DOM系统&#xff0c;用于高效地渲染和重新渲染组件。Vue以…

从 0 到 1 掌握部署第一个 Web 应用到 Kubernetes 中

文章目录 前言构建一个 hello world web 应用项目结构项目核心文件启动项目 检查项目是否构建成功 容器化我们的应用编写 Dockerfile构建 docker 镜像推送 docker 镜像仓库 使用 labs.play-with-k8s.com 构建 Kubernetes 集群并部署应用构建 Kubernetes 集群环境编写部署文件 总…

数据结构 【二叉树(上)】

谈到二叉树&#xff0c;先来谈谈树的概念。 1、树的概念及结构 树是一种非线性的数据结构&#xff0c;它的逻辑关系看起来像是一棵倒着的树&#xff0c;也就是说它是根在上&#xff0c;而叶子在下的&#xff0c; 在树这种数据结构中&#xff0c;最顶端的结点称为根结点。在树的…

Error: Invalid version flag: if 问题排查

问题描述&#xff1a; 国产化系统适配&#xff0c;arm架构的centos 在上面运行docker 启动后需要安装数据库 依赖perl 在yum install -y perl 时提示&#xff1a; “Error: Invalid version flag: if”

QML学习 —— 34、视频媒体播放器(附源码)

效果 说明 您可以单独使用MediaPlayer播放音频内容(如音频),也可以将其与VideoOutput结合使用以渲染视频。VideoOutput项支持未转换、拉伸和均匀缩放的视频演示。有关拉伸均匀缩放演示文稿的描述,请参见fillMode属性描述。 播放可能出错问题 出现的问题:      DirectS…

架构-微服务-服务网关

文章目录 前言一、网关介绍1. 什么是API网关2. 核心功能特性3. 解决方案 二、Gateway简介三、Gateway快速入门1. 基础版2. 增强版3. 简写版 四、Gateway核心架构1. 基本概念2. 执行流程 五、Gateway断言1. 内置路由断言工厂2. 自定义路由断言工厂 六、过滤器1. 基本概念2. 局部…

洛谷 P1722 矩阵 II C语言 记忆化搜索

题目&#xff1a; https://www.luogu.com.cn/problem/P1722 我们按照案例画一下 我们会发现&#xff0c;会出现重复的子结构。 代码如下&#xff1a; #include<iostream> using namespace std; int mem[300][300]; int n; int f[305][305]; int dfs(int x,int red,…

PICO 获取设备号 SN码

Unity版本 2020.3.42f1c1PICO SDK版本PICO Unity Integration SDK-3.0.5-20241105Pico设备pico 4ultra 注意 此api暂时只测试企业版本 pico 4ultra 代码 using Unity.XR.PICO.TOBSupport;private void Awake() {bool result PXR_Enterprise.InitEnterpriseService();Debug.L…

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

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

解决Flink读取kafka主题数据无报错无数据打印的重大发现(问题已解决)

亦菲、彦祖们&#xff0c;今天使用idea开发的时候&#xff0c;运行flink程序&#xff08;读取kafka主题数据&#xff09;的时候&#xff0c;发现操作台什么数据都没有只有满屏红色日志输出&#xff0c;关键干嘛&#xff1f;一点报错都没有&#xff0c;一开始我觉得应该执行程序…

零基础3分钟快速掌握 ——Linux【终端操作】及【常用指令】Ubuntu

1.为啥使用Linux做嵌入式开发 能广泛支持硬件 内核比较高效稳定 原码开放、软件丰富 能够完善网络通信与文件管理机制 优秀的开发工具 2.什么是Ubuntu 是一个以桌面应用为主的Linux的操作系统&#xff0c; 内核是Linux操作系统&#xff0c; 具有Ubuntu特色的可视…

xiaolin coding 图解网络笔记——TCP篇

1. TCP 头格式有哪些&#xff1f; 序列号&#xff1a;在建立连接时由计算机生成的随机数作为其初始值&#xff0c;通过 SYN 包传给接收端主机&#xff0c;每发送一次数据&#xff0c;就【累加】一次该【数据字节数】的大小。用来解决网络包乱序问题。 确认应答号&#xff1a;指…