【Leetcode-python】3.Longest Substring Without Repeating Characters(最长不重复连续子字符串)

题目:给定一个字符串,输出没有重复字符的最长子字符串的长度。
例:Input: "abcabcbb" Output: 3       Explanation: The answer is "abc", with the length of 3.
       Input: "bbbbb"       Output: 1       Explanation: The answer is "b", with the length of 1.
       Input: "pwwkew"   Output: 3        Explanation: The answer is "wke", with the length of 3.

需要注意: 考虑字符串长度为0的情况

思路:
       首先将字符串转化成list,写一个 从list不同索引开始 获取没有重复子字符串的递归函数getSubstring。计算所有的不重复子串的长度,存入列表list_len里,最后取出list_len里最大的元素值,即为最长子字符串的长度。
       getSubstring的实现方法为,将start位置的字符放入子串,接着看它的下一个位置是否存在与子串中,如果不存在就加入子串,如果存在,子串结束,返回重复字符位置。那么下一个子串是从什么位置开始的呢?例“abcabcbb”,寻找第一个子串,start=0,索引i=3的‘a’与i=1的‘a’重复,子串停止增加,第一个子串是“abc”,下一个子串是“bca”,……所以下一子串的start位置是,与当前子串“abc”中重复字符“a”的下一位置,即下一子串的start=1。

代码如下,但是此方法太过繁琐,时间复杂度和空间复杂度都很高。

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        def getSubstring(start):
            substr=ls[start]
            len_ls=len(ls)
            for i in range(start+1,len_ls):
                if ls[i] not in substr:
                    substr+=ls[i]
                else:
                    next_start=ls[start:i].index(ls[i])+1+start
                    return i,next_start
            return len_ls,-1
        ls=list(s)
        len_ls=len(ls)
        if len_ls>0:
            list_len=[]
            start=0
            end,next_start=getSubstring(start)
            while(end<len(ls)):
                list_len.append(end-start)
                start=next_start
                end,next_start=getSubstring(start)
            list_len.append(end-start)
            return max(list_len)
        else:
            return 0

有没有更简单的方法呢,再看讨论贴的时候,发现了时间复杂度为O(N)的方法,真是厉害了,代码居然如此简洁。其中b是不重复子字符串的起始位置,m是之前步骤中子字符串的最大长度,d字典。

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        #b: begin m: max length in previous step d: dictionary
        b, m, d = 0, 0, {}
        for i, char in enumerate(s): 
            b, m, d[char] = max(b, d.get(char, -1) + 1), max(m, i - b), i
            #多重赋值操作的等号右边表达式会在赋值操作之前全部进行解析,所以右侧表达式用到的b,d,m均 
             是上一次循环的结果
            #等价于m=max(m, i - b),b=max(b, d.get(l, -1) + 1),d[l]= i
        return max(m, len(s) - b)

Input: "pwwkew",代码的每次循环运行结果如下:
  
此方法是利用 for (i,char) in enumerate(s) 同时使用下标和元素直接对字符串进行循环,每次循环将字符char作为key,对应下标作为value存入字典d中,如果存在重复字符,字典中的value不断更新。如果下一次循环到的字符char不存在与字典中,则当前子字符串长度i-b继续增加,起始位置b不变;如果下一次循环到的字符char存在与字典中,则当前子字符串结束,起始位置b变成下一子字符串的起始位置(当前子字符串中重复字符的下一位置,d.get(char,-1) + 1,表示返回指定键的值,如果值不在字典中返回-1)。此方法的优势是:没有将字符串转成list,而是直接循环;使用字典存储字符和位置,而不是list,巧妙利用了重复字符index会更新;没有涉及具体生成的字符串是什么,只关注起始位置,通过一次循环寻找结束位置,并不断更新长度最大值。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值