「本文已参与好文召集令活动,点击查看:后端、大前端双赛道投稿,2万元奖池等你挑战!」
题目如下:
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
题目要求找出给定字符串中不含重复字符的最长子串,我们可以采用暴力穷举的方式,得到字符串中的所有子串,然后一一判断不重复子串的长度,最后返回最长子串的长度即可,比如:
对于这样的一个字符串,我们首先从头开始进行遍历,将a取出:
然后取出下一个字符b,查看该字符是否重复,若不重复,继续放入新的字符串中:
下一个字符c也是如此:
紧接着下一个字符是a,此时发现新字符串中已经有了字符a,发生了重复,所以现在记录一下新字符串的长度,为3,然后从原字符串的第二个字符开始继续进行遍历:
再看下一个字符c,仍然放入新字符串:
直至遇到字符b,又产生了重复:
此时仍然记录当前新字符串的长度,并从原字符串的第三个字符开始遍历:
以此类推,就得到了一个无重复字符子串的长度表:
此时只需取出长度表中的最大值,即为字符串中无重复字符的最长子串长度。
清楚了算法思想之后,就可以写出代码:
1 | java复制代码public static int lengthOfLongestSubstring(String s) { |
将代码进行提交,结果出错:
原来我们没有考虑什么都不输入的情况,若无输入,则直接返回长度0即可,对于长度为1的输入,我们也得单独考虑,因为刚才的程序只有在出现重复字符的时候才会记录当前子串的长度,而如果输入字符串的长度为1,就没有重复的情况了,所以单独处理这两种情况即可,修改代码:
1 | java复制代码public static int lengthOfLongestSubstring(String s) { |
测试通过:
暴力穷举虽然解决了题目需求,但执行效率非常低,为此,这里再介绍另外一种解决方案:滑动窗口。
对于这样的一个字符串:
我们设置一个滑动窗口,该窗口内的子串就是无重复字符的最长子串,定义两个指针用于划分窗口的左边界和右边界,并指定此时最长子串长度为1:
让right指针右移,扩大滑动窗口范围,此时最长子串长度为2:
继续右移right指针,最长子串长度为3:
当再次右移right指针时,发现字符a已经在滑动窗口中出现:
此时我们需要缩小滑动窗口,使其不再与当前字符a重复,让left指针右移:
当滑动窗口已不再与字符a重复后,扩大滑动窗口,right右移,此时最长子串长度仍为3:
此时又发现字符b与窗口中的字符重复,继续缩小滑动窗口:
无重复后,扩大滑动窗口,right指针右移:
以此类推,直到遍历结束。
代码如下:
1 | java复制代码public static int lengthOfLongestSubstring(String s) { |
测试通过:
该算法仍然有可以改进的地方,比如:
对于这样的一个字符串,当滑动窗口遇到重复字符:
此时缩小滑动窗口,left要一直右移,直至将字符w删除:
那么有没有办法能够让left直接移动到重复字符的下一个字符呢?我们可以改用HashMap来模拟滑动窗口,因为HashMap可以存储一个值,我们就让它存储字符的索引即可。
所以当遇到重复字符w时,直接从HashMap中取出滑动窗口中w的索引3,然后直接让left指针跳转至下一个索引4的位置即可。
代码如下:
1 | java复制代码public static int lengthOfLongestSubstring(String s) { |
本文转载自: 掘金