《剑指offer》刷题系列——(六十)最长不含重复字符的子字符串

题目

请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。
示例 :
输入: “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
>>>

猜你喜欢

转载自blog.csdn.net/weixin_44776894/article/details/107485146