题目
请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。
示例 :
输入: “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
思路
动态规划的思想
动态转移方程:
dp[j]表示以第j个字符结尾的最长不含重复字符的子字符串
i 表示距离第j个字符最近的相同字符的索引
如果j-i > dp[j-1],说明s[i]在当前计算的最长子字符串范围之外,dp[j] = dp[j-1]+1
如果j-i <= dp[j-1],说明s[i]在当前计算的最长子字符串范围内,dp[i] = j-i
字典的定义是为了更快地找到s[i]的位置。
代码
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
dic = {}
res = tmp =0
for j in range(len(s)):
i = dic.get(s[j],-1)
dic[s[j]] = j
if j-i > tmp:
tmp = tmp + 1
else:
tmp = j-i
res = max(res,tmp)
return res
官方版
函数f(i)表示以第i个字符结尾的不包含重复字符的子字符串的最长长度.
从左到右逐一扫描每个字符.
如果s[i]之前没有出现过,则f(i)=f(i-1)+1;
如果s[i]之前出现过,我们先计算s[i]和它上次出现在字符中的位置的距离记为d.然后分两种情况讨论:
第一种情形是d<=f(i-1),此时s[i]上次出现在f(i-1)对应的最长子字符串之中,因此f(i)=d.
第二种情形是d>f(i-1),此时s[i]上次出现在f(i-1)对应的最长子字符串之前,因此f(i)=f(i-1)+1.
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
if len(s)==0: return 0
dic={}
cur_length=0
max_length = 0
for i in range(len(s)):
# 当前字符没有出现过
if s[i] not in dic:
cur_length+=1
# 当前字符出现过
else:
#当前字符与它上次出现的位置之间的距离
dis = i-dic[s[i]]
# 距离小于等于f(i-1)
if dis<=cur_length: cur_length=dis
# 距离大于f(i-1)
else: cur_length+=1
# 更新当前字符的最新位置
dic[s[i]]=i
# 保存整个过程的最大长度
if max_length<cur_length:
max_length=cur_length
return max_length
复杂度
时间复杂度 O(N): 其中 N 为字符串长度,动态规划需遍历计算 dp 列表。
空间复杂度 O(1): 字符的 ASCII 码范围为 0 ~ 127,哈希表 dic最多使用 O(128)=O(1)大小的额外空间。
知识点
Python 字典(Dictionary) get()方法
# dict.get(key, default=None),返回指定键的值,如果值不在字典中返回默认值None。
>>> dic = {'a':1,'b':5}
>>> dic.get('c',-1)
-1
>>> dic.get('b')
5
>>>