动态规划法,需要考虑三个因素:
- 状态表示 本题 $\text{dp[i]}$ 表示以第 $\text{i}$ 个元素结尾的不含重复字符的最大子串长度;
- 状态转移方程 如果第 $\text{i}$ 个元素,在前 $\text{i-1}$ 个元素中未出现,我们可以直接将第 $\text{i}$ 个元素加入到上一个最大子串中,此时 dp[i] = dp[i-1]+1;如果第 $\text{i}$ 个元素,在前 $\text{i-1}$ 个元素中已出现,那么我们需要计算,在前 $\text{i-1}$ 个元素中,最近一次出现第 $\text{i}$ 个元素的位置,并计算出二者的间距$\text{distance}$。如果 $\text{distance>dp[i-1]}$,说明重复的元素不影响当前不含重复字符的最大子串长度,所以 dp[i] = dp[i-1]+1,如果$\text{distance}\leq\text{dp[i-1]}$,说明以第 $\text{i}$ 位 元素结尾的,最大无重复字符的子串,是从上一个重复元素的下一位开始,到当前第 $\text{i}$ 位元素结束,此时dp[i] = distance
- 边界条件 当 $\text{i=0}$ 时,$\text{dp[0] = 1}$
在本题中,需要记录第 $\text{i}$ 个元素有无出现过,如果出现过,它最近一次出现的位置在哪,所以我们可以创建一个字典结构,来保存上述信息。
python3 代码
class Solution:
def longestSubstringWithoutDuplication(self, s):
"""
:type s: str
:rtype: int
"""
if not s:
return 0
dp = [0] * len(s) #dp[i]表示以第i个元素结尾的不含重复字符的最大子串长度
d = dict() # 用来记录26个字母,上一次出现的位置
res = 0
for i in range(0,len(s)):
if s[i] not in d.keys(): # 第i个元素在之前未出现
dp[i] = dp[i-1]+1
else:
distance = i - d[s[i]]
if distance > dp[i-1]:
dp[i] = dp[i-1]+1
else:
dp[i] = distance
d[s[i]] = i # 更新第i个元素最后出现的位置
res = max(res,dp[i])
return res