[LeetCode] Longest Substring Without Repeating Characters


发布于

|

分类

题意

给一个字符串,求它的最长不重复子串的长度。

题解

第一想法:DP,我不会。

第二想法:DP,我不会……

然后慢慢想:假设现在前面已经处理过一些字符串了,现在来到了第 i 个字符处。最简单的情况,如果这个字符在前面已经处理过的字符串中没有出现过,怎么办?直接 extend 进去,当前长度 + 1,然后把这个字符最后出现的位置记录下来。

如果这个字符之前出现过,怎么办?这里就要分成两种情况了。我直接画图说明吧。图中 | 代表当前不重复的字符串,+ 代表当前字符,o 代表这个字符上一次出现的位置。

第一种情况:

____|______o______|+

这种情况下,就要缩短不重复字符串的长度了。新的不重复字符串是从 o 后面一个字符开始,到当前字符 + 截止。

第二种情况:

o___|_____________|+

也就是说,重复点不在当前不重复字符串内。那么好啊,对于当前不重复字符串来说,字符 + 没有出现过。直接 extend,长度 + 1。

还有其他情况了么?没有了。

如果硬要用 DP 数组记录下来上面的 “长度” 信息的话,那么 f 数组的含义是 “以第 i 个字符为结尾的最长不重复字符串的长度”。这样说清楚么?

下面一个问题,字符 + 之前在那儿出现过,怎么记录?

字典啊!别忘了你现在用的是 Python!字典的查找可是 $O(1)$ 级别的运算啊!

代码

class Solution(object):
    def lengthOfLongestSubstring(self, s):
        """
        :type s: str
        :rtype: int
        """
        last_show = dict()
        answer = 0
        now_length = 0
        for ith in range(len(s)):
            ch = s[ith]
            if ch not in last_show:
                now_length += 1
                # It's easy             :       ____|_____________|+
            else:
                now_length = min(ith - last_show[ch], now_length + 1)
                # ith - last_show[ch]   :       ____|______+______|+
                # now_length + 1        :       +___|_____________|+

            last_show[ch] = ith
            # Update ans
            answer = max(answer, now_length)

        return answer

结果

982 / 982 test cases passed.
Status: Accepted
Runtime: 124 ms

982 个测试点…… 也是丧心病狂啊!

其他解法

如果你崇尚暴力…… 那就暴力着来吧:枚举起点、终点,截取字符串,看看有没有重复的字符,有的话就丢掉,没有的话比较长度。时间大概是 $O(n^3)$ 。

如果你不想那么暴力…… 还可以温柔一点:枚举起点、终点,看看有没有重复的字符,有的话就丢掉,没有的话记录最大长度。然后继续枚举起点的时候,长度至少比当前最大长度要长。时间大概也是 $O(n^3)$ 。

有人说,用滑动窗口:维护一个不重复子串窗口,新来一个字符,在窗口内判重,不重就增加窗口长度,重复就把重复点之前的东西全删除。其实和我的想法是一样的。不过这个做法时间接近 $O(n^2)$ 了。不太划算。

还有各种 DP 的方案我就看不懂了……

桩程序

if __name__ == '__main__':
    cases = [
        {'s': "tmmzuxt", 'ans': 5},
        {'s': "aab", 'ans': 2},
        {'s': "abba", 'ans': 2},
        {'s': "abcabcbb", 'ans': 3},
        {'s': "bbbbb", 'ans': 1},
        {'s': "blqsearxxxbiwqa", 'ans': 8},
        {'s': "absd", 'ans': 4},
        {'s': "abcabcbb", 'ans': 3},
        {'s': "abdffd", 'ans': 4},
    ]

    for item in cases:
        ans = (Solution()).lengthOfLongestSubstring(s=item['s'])

        print(item['s'])
        print(str(ans == item['ans']) + "\t=>" + str(ans) + ":" + str(item['ans']))

评论

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注