版权申明:原创文章,未经博主同意,不得转载!
Longest Substring Without Repeating Characters(无重复字符的最长子串),其内容如下:
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。示例 2:
输入: "bbbbb" 输出: 1 解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。示例 3:
输入: "pwwkew" 输出: 3 解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。 请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。仔细阅读题目,要求是在给定的字符串中找到最长的无重复字符子串,题目给了三个示例,已经很明白的说明了要求。下面我们就思考如何解决这个问题。对于我们来说,给定一个字符串,如示例1中“abcabcbb”,如何寻找最长无重复子串呢?肯定要从给定的字符串起点开始向后遍历,一直遇到已经出现过的字符,如a,b,c,a,这时又出现a,出现了重复字符,我们可以记录当前的最长子串长度为3。
在示例1中,第一次出现的重复字符是a,是在当前记录子串的第1位,我们不妨假设一下,如果出现的字符不是a而是b或c呢?
可以看到,这样三种情况已经包含了重复字符出现的所有位置,针对更长的子串也是这样,就是开头、中间和尾部三种情况。但不论重复字符出现在哪个位置,它都表示当前记录子串的结束。而对于出现的重复字符位置,其实可以归结为一种情况,可以将其看做为寻找下一子串的起点。
按照上面的思路,编写了如下代码:
class Solution: def lengthOfLongestSubstring(self, s: str) -> int: # 记录当前子串的长度 length = 0 # 记录当前无重复字符最长子串的长度 maxlen = 0 # 遍历字符串 for i in range(len(s)): # 设定当前子串长度为1 length = 1 # 从指定起始位置开始遍历 for j in range(i+1, len(s)): # 如果当前字符重复字符 if s[j] in s[i:j]: # 指定下一子串遍历位置,跳出循环 i += (s[i:j].index(s[j])+1) break # 不是重复字符 else: # 当前子串长度加1 length += 1 # 记录最大长度 if length > maxlen: maxlen = length return maxlen运行结果:
感觉我们的方法还是可以的啊,但是为什么速度这么慢?还是算法有问题吗。所以赶紧找网上的大神博客看一下,LeetCode官方也提供了题解。官方题解
看了之后,我们的方法可以称之为滑动窗口。而且我们的算法还可以进一步优化。当我们遇到重复字符之后,我们得到了下一子串的起点位置,但是我们并不需要在从起点位置进行遍历,因为我们可以确定在起点到当前重复字符之间没有其他重复字符,所以我们可以直接从重复字符位置作为向后遍历的起点。
修改代码:
class Solution: def lengthOfLongestSubstring(self, s: str) -> int: # 记录当前无重复字符最长子串的长度 maxlen = 0 i = 0 # 遍历字符串 for j in range(0, len(s)): # 出现重复字符 if s[j] in s[i:j]: # 指定下一子串遍历起点位置 i += (s[i:j].index(s[j])+1) # 无重复字符 else: # 更新最大长度 maxlen = max(maxlen, j-i+1) return maxlen在代码中,我们去掉了最外层循环,原来的内层循环使用相对位置现在变为绝对位置,改变了最大长度值的更新方式。
运行结果:
还是要多学习别人的方法,这样的写出来的代码颜值高而且有内涵。
这道Longest Substring Without Repeating Characters的解法就介绍到这里。
以上。
本期到此结束,扫下面二维码加Python学习公众号,有海量优质学习资源!