【手绘算法】力扣 3 无重复的最长字符串(Longest Substring Without Repeating Characters)

简介: Hi,大家好,我是Tom。一个美术生转到Java开发的程序员。今天给大家分享的是力扣题第3题,无重复的最长字符串。在解题过程中,也会手写一些伪代码。当然,如果想要完整的源码的话,可以到我的个人主页简介中获取。这道题呢属于中等难度,评估为四颗星,它的通过率只有39%。

Hi,大家好,我是Tom。一个美术生转到Java开发的程序员。今天给大家分享的是力扣题第3题,无重复的最长字符串。在解题过程中,也会手写一些伪代码。当然,如果想要完整的源码的话,可以到我的个人主页简介中获取。

这道题呢属于中等难度,评估为四颗星,它的通过率只有39%。

5b3bde6e90ed4e83a1030d69fbcd7ceb.png

1、题干分析

首先,我们还是来分析一下这道题的题干。它说的是,给定一个字符串 s,让我们来找出不含重复字符的 最长子串 的长度。注意,这个地方不重复的最长子串是指它其中连续的字符串的部分。比如说,官方给了几个示例,我看第1个示例:

d42f236b78df4c4cab1fa3d8eedeebf1.png

对于这道题,我给出两种解题方法。第一种方法是暴力法求解,第二种方法是滑动窗口求解。

a346975f9d1649c7a1d047c9fabd8fa0.png

2、暴力法求解

首先,我们来分析一下暴力法求解的思路。这个答案我们目测,最长不重复子串为 bacd ,它的长度为4。但是程序怎么才能判断出来呢?其实暴力法的逻辑分厂简单,就是字符串中的每个字符和后面的进行比较,一直累计不重复的次数,最后,将累计最大的值返回。

首先,我们定义一个方法叫 checkUnique(),专门用来检测是否重复,如果重复就返回 fasle ,如果不重复就返回 true。

然后,我们用两个循环,依次比较,比如第一层循环游标为 i,第二层循环游标为 j。

第一轮比较的游标值为 i = 0,j = 1。首先拿 a 和 b 比较,发现不重复就累加,然后,a 和 c 比较发现不重复,继续累加。然后,a 和 b比较依次类推。

第一轮比较完成之后,进行第二轮比较,游标值 i = 1,j = 2, 也就是拿 b 和 c 比较,不重复累加,b 和 b 比较重复 不累加,然后b 和 a比较以此类推。

最后,依次比到第九轮,i = 8,j = 9,我们最终得到累计的最大值。

976bd202dfe04a5f81442e443940b8f6.png

这是暴力法求解的伪代码:

5f6e9af90604439f860ca6c9f95ee2da.png

当然,暴力求解法是最笨的方法,也是效率最低的办法,我不推荐使用。

3、滑动窗口求解

下面,给大家介绍一种更高效的解法,滑动窗口求解,也叫双指针求解,我们先来理解一下滑动窗口的解题思路。我们定义一个左指针 left 和右指针 right 进行实时地滑动,一般情况下这两个指针都是往右滑动。右指针最先开始滑动,只要满足条件就会一直往右滑动,当不满足条件的时候,左指针才开始往右滑动,直到能让右指针满足条件为止。那么,左指针和右指针之间的区间,我们就可以理解为滑动的窗口。当然,这个滑动的窗口可以是固定宽度,也可以是可变宽度。

b7072d283eab4055bf08bd95478694de.png假设有这样一个字符串 “ abcbacdca ”,下面我们利用滑动窗口的思想来快速找到这个字符串中不重复的最长子串。最开始的时候,我们把左指针和右指针同时指向这个字符串的首位置。同时,我们还定义一个 length 来记录当前遍历到的当前窗口的长度,默认赋值为字符串的长度为8。然后,定义 maxLength ,表示当前不重复子字符串的最大长度用于结果输出,默认为 0。然后,还要定义一个数组 window,用于标记窗口中的元素。这个数组的长度我固定为128,因为,一会我将要利用字符的 ASCII 码作为数组的索引下标,然后,在数组对应的下标位置坐标记。而 ASCII 码的 范围 0- 127,也就是128个值,正好覆盖到所有的字符。

792d4557ab1b41b39892b8db679f7182.png

首先是右指针就要开始往后移动。右指针每遍历到一个元素呢,它都要放入到 window 中,如果发现 window 中已经存在遍历过的元素,说明,左指针就要往后移动。

接下来,我们来模拟程序的执行逻辑。首先,左指针 和 右指针默认都指向 a 这个字符。

第一步,将右指针指向的 a 字符放入到 window 中,而 a 的 ASCII 码是 97,所以在下标为 97 的位置标记为 1,表示 a 出现的位置为 1。maxLength 加 1更新为1,同时,右指针往后移动。

第二步,将右指针指向的 b 字符放到入到 window 中,下标为 98 的位置,并且标记为 2,表示 b 出现的位置为 2。maxLength 加 1更新为2,同时,右指针继续往后移动。

第三步,将右指针指向的 c 字符放入到 window 中,下标为 99 的位置,并且标记为 3,表示 c 出现的位置为 3。maxLength 加 1更新为3,同时,右指针继续往后移动。

第四步,将右指针指向的 b 字符放入到 window 中,下标为 98 的位置,这个时候,发现 b 在前面出现过,所以,左指针要移动到 b 上一次出现的位置之后,也就是 c 的位置下标为 2。然后,再将下标为 98 的值更新为 b 出现的位置为 4,同时,右指针继续往后移动。

第五步,将右指针指向的 a 字符放入到window中,下标为 97 的位置,这个时候,我们又发现 a 在之前出现过,所以,左指针又要移动到 a 上次出现的位置之后,也就是 b 的位置下标为 1。然后,再将下标为 97 的值更新为 a 出现的位置为 5,同时,右指针继续往后移动。

第六步,将右指针指向的 c 字符放入到window中,下标为 99 的位置,这个时候,我们又发现 c 在之前出现过,所以,左指针又要移到 c 上次出现的位置之后,也就是 b 的位置,下标为 3。然后,再将下标为 99 的值更新为 c 出现的位置为 6,同时,右指针继续往后移动。

第七步,将右指针指向的 d 字符放入到 window中,下标为 100 的位置,d 在之前没有重复出现,所以将 99 的值标记为 d 出现的位置为7,左指针保持不动,maxLength 加 1 更新为 4,右指针继续往后移动。

第八步,将右指针指向的 c 字符放入到window中,下标为 99 的位置,这时我们又发现 c 在之前出现过,所以,左指针又要移到 c 上次出现的位置之后,就是 d 的位置,下标为 6。然后,再将下标为99的值更新为 c 出现的位置为 8,同时,右指针继续往后移动。

第九步,将右指针指向的 a 字符放入到windown中,下标为 97 的位置,这时我们发现 a 又在之前出现过,所以,左指针又要移动 a 上次出现的位置之后,也就是 c 的位置,下标为 5,然后,再将下标为 97 的值更新为 a出现的位置为9,同时,右指针继续往后移动。

这时候,右指针已经超出了字符串的范围,所以,最终maxLength的值顶格在 4。

5150013eea9c47c6909b92de6cfc4970.png

这是滑动窗口求解的伪代码:

feaf55ab783347e39a4729e9d97455a1.png

以上就是我对于无重复的最长字符串这道题的解题思路分享。只要是遇到字符串查找相关的问题,利用双指针有非常好的适用性。这道题除了滑动窗口求解以外,其实还可以使用动态规划等方法求解。如果需要完整代码的小伙伴,可以在我的个人主页简介中获取。

0b055dbf77b44ec7ac5125e3ecda03d2.png

我是被编程耽误的文艺Tom,如果我的分享对你有帮助,请动动手指一键三连分享给更多的人。关注我,面试不再难!

相关文章
|
11天前
|
自然语言处理 算法 搜索推荐
字符串相似度算法完全指南:编辑、令牌与序列三类算法的全面解析与深入分析
在自然语言处理领域,人们经常需要比较字符串,这些字符串可能是单词、句子、段落甚至是整个文档。如何快速判断两个单词或句子是否相似,或者相似度是好还是差。这类似于我们使用手机打错一个词,但手机会建议正确的词来修正它,那么这种如何判断字符串相似度呢?本文将详细介绍这个问题。
181 1
|
13天前
|
数据采集 算法 JavaScript
揭开JavaScript字符串搜索的秘密:indexOf、includes与KMP算法
JavaScript字符串搜索涵盖`indexOf`、`includes`及KMP算法。`indexOf`返回子字符串位置,`includes`检查是否包含子字符串。KMP是高效的搜索算法,尤其适合长模式匹配。示例展示了如何在数据采集(如网页爬虫)中使用这些方法,结合代理IP进行安全搜索。代码示例中,搜索百度新闻结果并检测是否含有特定字符串。学习这些技术能提升编程效率和性能。
揭开JavaScript字符串搜索的秘密:indexOf、includes与KMP算法
|
17天前
|
算法
力扣每日一题 6/23 字符串/模拟
力扣每日一题 6/23 字符串/模拟
11 1
|
17天前
|
存储 算法 搜索推荐
力扣每日一题 6/13 反悔贪心算法
力扣每日一题 6/13 反悔贪心算法
12 1
|
17天前
力扣经典150题第四十题:同构字符串
力扣经典150题第四十题:同构字符串
12 1
|
28天前
|
算法 Java
[Java·算法·简单] LeetCode 283. 移动零
[Java·算法·简单] LeetCode 283. 移动零
23 2
|
17天前
|
索引
力扣每日一题 6/27 字符串 贪心
力扣每日一题 6/27 字符串 贪心
8 0
|
17天前
|
Python
力扣随机一题 模拟+字符串
力扣随机一题 模拟+字符串
8 0
|
17天前
力扣每日一题 6/22 字符串/贪心
力扣每日一题 6/22 字符串/贪心
6 0
|
17天前
力扣每日一题 6/18 字符串/模拟
力扣每日一题 6/18 字符串/模拟
9 0