【手绘算法】力扣 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,如果我的分享对你有帮助,请动动手指一键三连分享给更多的人。关注我,面试不再难!

相关文章
|
1月前
|
算法
【算法】滑动窗口——找到字符串中所有字母异位词
【算法】滑动窗口——找到字符串中所有字母异位词
|
28天前
|
算法
测试工程师的技能升级:LeetCode算法挑战与职业成长
这篇文章通过作者亲身体验LeetCode算法题的过程,探讨了测试工程师学习算法的重要性,并强调了算法技能对于测试职业成长的必要性。
42 1
测试工程师的技能升级:LeetCode算法挑战与职业成长
|
1月前
|
算法 Java
掌握算法学习之字符串经典用法
文章总结了字符串在算法领域的经典用法,特别是通过双指针法来实现字符串的反转操作,并提供了LeetCode上相关题目的Java代码实现,强调了掌握这些技巧对于提升算法思维的重要性。
|
1月前
|
机器学习/深度学习 算法 计算机视觉
【博士每天一篇文献-算法】持续学习经典算法之LwF: Learning without forgetting
LwF(Learning without Forgetting)是一种机器学习方法,通过知识蒸馏损失来在训练新任务时保留旧任务的知识,无需旧任务数据,有效解决了神经网络学习新任务时可能发生的灾难性遗忘问题。
78 9
|
1月前
|
存储 算法
LeetCode第43题字符串相乘
LeetCode第43题"字符串相乘"的解题方法,通过使用数组存储乘积并处理进位,避免了字符串转换数字的复杂性,提高了算法效率。
LeetCode第43题字符串相乘
|
1月前
|
算法 Java
LeetCode第28题找出字符串中第一个匹配项的下标
这篇文章介绍了LeetCode第28题"找出字符串中第一个匹配项的下标"的两种解法:暴力解法和KMP算法,并解释了KMP算法通过构建前缀表来提高字符串搜索的效率。
LeetCode第28题找出字符串中第一个匹配项的下标
|
1月前
|
算法
LeetCode第8题字符串转换整数 (atoi)
该文章介绍了 LeetCode 第 8 题字符串转换整数 (atoi)的解法,需要对字符串进行格式解析与校验,去除前导空格和处理正负号,通过从高位到低位的计算方式将字符串转换为整数,并处理越界情况。同时总结了这几道题都需要对数字的表示有理解。
LeetCode第8题字符串转换整数 (atoi)
|
1月前
|
算法 Java
LeetCode经典算法题:矩阵中省份数量经典题目+三角形最大周长java多种解法详解
LeetCode经典算法题:矩阵中省份数量经典题目+三角形最大周长java多种解法详解
36 6
|
1月前
|
存储 算法 Java
LeetCode经典算法题:打家劫舍java详解
LeetCode经典算法题:打家劫舍java详解
46 2
|
1月前
|
人工智能 算法 Java
LeetCode经典算法题:井字游戏+优势洗牌+Dota2参议院java解法
LeetCode经典算法题:井字游戏+优势洗牌+Dota2参议院java解法
37 1