【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

有没有更简单的方法呢,再看讨论贴的时候,发现了时间复杂度为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",代码的每次循环运行结果如下:
  【Leetcode-python】3.Longest Substring Without Repeating Characters(最长不重复连续子字符串)_第1张图片
此方法是利用 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会更新;没有涉及具体生成的字符串是什么,只关注起始位置,通过一次循环寻找结束位置,并不断更新长度最大值。

你可能感兴趣的:(算法)