LeetCode第3题:无重复字符的最长子串
Ps:本系列文章只为记录自己刷LeetCode过程中的解题过程和思路。
题目描述:
给定一个字符串,请你找出其中不含有重复字符的最长子串的长度。
示例 1:
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是"wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke"是一个子序列,不是子串。
解题过程和思路:
这道题的题目很明确,就是找序列中的无重复字符的最长子串。暴力解法的思路很简单:遍历序列,假设序列中的每个字符都可能为所求最长子串的第一个字符,每个字符都往后遍历得到最长的子串,总共可以得到n个子串,最后比较各子串的长度即可。然而,偷偷看了大佬们的做法之后,发现了一个滑动窗口很巧妙的应用:每次发现重复肯定是窗口中已有不重复序列中的某个字符和新探索的字符重复发生了冲突,那么每次在发生冲突的时候将窗口中的那个字符以及之前的字符踢出滑动窗口即可,窗口每滑动一步便记录当前窗口大小和历史窗口大小的长度,大者为当前探索得到的最长子串长度。待窗口滑动到序列的最右端,我们也可以找出最长子串的长度了。(同样地可以用字典来建模,提高在窗口中重复节点的搜索速度。)
解题收获:
滑动窗口的应用,记住啦。
代码展示:
class Solution(object):
def lengthOfLongestSubstring(self, s):
# 滑动窗口解法
"""
:type s: str
:rtype: int
"""
max_l = 0 # 记录目前搜索到的最大字串长度
p1 = p2 = 0 # 双指针指示滑动窗口的两端,窗口内的字串长度为 p2-p1
d = {} # 利用字典记录目前搜索到的元素,用来查找是否有重复(将元素值作为键值,用字典查找快啊)
for index, c in enumerate(s): # 遍历一遍字符串
if c not in d:
d[c] = index # 如果当前字符不在字典中就加入,键值为元素值
p2 += 1 # 窗口右指针向右滑动1格
else:
if d[c] + 1 > p1: # 两个指针都只能往右移动,如果不是很懂,“abba” 人工模拟这种情况即可
p1 = d[c] + 1 # 右指针移动到重复的元素的右边一位,将左边的重复元素踢出窗口
p2 += 1 # 右指针继续往右滑动1格
d[c] = index # 字典记录重复元素的最新的索引值
max_l = max(p2-p1, max_l) # 对比当前最大长度和历史最大长度,替换历史最大长度
return max_l
结果展示: