在问 · 算法题解

3. 无重复字符的最长子串

中等滑动窗口滑动窗口(记录下标跳跃)力扣原题 ↗

题目描述

输入一个字符串 s。子串指 s 中一段连续的字符。

在所有内部没有重复字符的子串里,找出最长的一个,返回它的长度。s 为空时返回 0。

示例 1
输入:s = "abcabcbb"
输出:3

解释:"abc" 没有重复字符,长度为 3;再长就一定出现重复。

示例 2
输入:s = "bbbbb"
输出:1

解释:每个子串只要长度超过 1 就会重复,最长的是 "b"。

示例 3
输入:s = "pwwkew"
输出:3

解释:最长的是 "wke",长度 3。"pwke" 不连续,是子序列而不是子串。

数据范围

  • 0 <= s.length <= 10^5
  • s 中可能出现英文字母、数字、符号和空格。

解题思路:滑动窗口(记录下标跳跃)

右指针扩展窗口,记录字符最近出现位置;若重复字符落在窗口内,就把左边界跳到其后一位。

为什么正确

窗口 s[left:right+1] 始终没有重复字符,best 是已处理窗口的最大长度。

复杂度分析

时间 O(n),空间 O(min(n,字符集大小))。

易错点

重复字符在窗口外时不能把 left 向后跳错;要判断 last[ch] >= left。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def lengthOfLongestSubstring(self, s):
        last={}; left=0; best=0
        for right,ch in enumerate(s):
            if ch in last and last[ch] >= left: left=last[ch]+1
            last[ch]=right
            best=max(best,right-left+1)
        return best

载入编辑器,自己跑一遍 →

其他解法

两种做法都维护无重复字符的窗口;集合版逐步收缩左边界,下标表版直接跳跃左边界。

解法 2:滑动窗口 + 哈希集合 时间 O(n),空间 O(min(n,Σ))

用哈希集合保存窗口内的字符。右指针每读入一个字符,若它已在集合中,就不断移除 s[left] 并右移 left,直到重复字符离开窗口。然后把新字符加入集合,并用窗口长度更新答案。Σ 为字符集大小。

左边界一步一步收缩,每个字符最多进出集合各一次,仍是 O(n)。主解法记录最近下标,可以让左边界一次跳到位,常数更小;集合版的窗口收缩过程更直观。

class Solution:
    def lengthOfLongestSubstring(self, s):
        window = set()
        left = best = 0
        for right, ch in enumerate(s):
            while ch in window:
                window.remove(s[left])
                left += 1
            window.add(ch)
            best = max(best, right - left + 1)
        return best

滑动窗口 专题的其他题目

查看 滑动窗口 全部题目 →