无重复字符的最长子串

标签: 哈希表 字符串 滑动窗口

难度: Medium

给定一个字符串 s ,请你找出其中不含有重复字符的 最长连续子字符串 的长度。

示例 1:

输入: s = "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子字符串是 "abc",所以其长度为 3。

示例 2:

输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子字符串是 "b",所以其长度为 1。

示例 3:

输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
     请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。

示例 4:

输入: s = ""
输出: 0

提示:

  • 0 <= s.length <= 5 * 104
  • s 由英文字母、数字、符号和空格组成

注意:本题与主站 3 题相同: https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/

Submission

运行时间: 39 ms

内存: 16.2 MB

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        begin,end = 0,0
        tt = {}
        maxlen = 0
        for end in range(len(s)):
            if s[end] not in tt or tt[s[end]] < begin:
                tt[s[end]] = end 
                maxlen = max(maxlen,end-begin+1)
            else:
                ## 更新
                begin = tt[s[end]] + 1
                tt[s[end]] = end 
        return maxlen
                
                

Explain

题解采用的是滑动窗口技术来找出不含有重复字符的最长子串。维护两个指针(begin和end)作为窗口的边界,以及一个哈希表tt来记录每个字符最近一次出现的位置。随着end指针的遍历,如果当前字符s[end]未出现过或者其上一次出现的位置在窗口左边界begin之前,那么更新该字符的位置并计算当前窗口的长度。如果发现重复字符,即s[end]出现的位置在begin之后或等于begin,则更新begin到该字符上次出现位置的下一个位置,重新定义窗口的左边界。这样,每步都可能更新最长子串的长度。

时间复杂度: O(n)

空间复杂度: O(m)

    class Solution:
        def lengthOfLongestSubstring(self, s: str) -> int:
            begin, end = 0, 0  # 初始化窗口的左右边界
            tt = {}  # 哈希表,存储字符及其最新的索引位置
            maxlen = 0  # 记录最大长度
            for end in range(len(s)):
                if s[end] not in tt or tt[s[end]] < begin:
                    # 如果字符未出现过或出现位置在当前窗口左边界之前
                    tt[s[end]] = end  # 更新字符的最新位置
                    maxlen = max(maxlen, end - begin + 1)  # 更新最大长度
                else:
                    # 如果当前字符已存在于窗口中
                    begin = tt[s[end]] + 1  # 移动窗口的左边界到重复字符的下一个位置
                    tt[s[end]] = end  # 更新字符的最新位置
            return maxlen  # 返回最大长度
    

Explore

当遇到重复字符时,更新begin指针到重复字符的下一个位置是为了确保窗口中不包含任何重复字符,并且这种移动是最小的有效移动。将begin移动到这个位置可以保留窗口中尽可能多的非重复字符,从而有机会在接下来的扩展中寻找更长的无重复子串。如果移动到其他位置,比如重复字符之前或更远的位置,将不必要地缩小窗口大小或错过潜在的最长无重复字符子串。

在哈希表tt中,字符的索引位置每次遇到该字符时都会更新。无论该字符是否在当前窗口内,只要字符被遍历到,其在哈希表中的索引就会被更新为当前的索引。这样做可以确保不管窗口如何移动,哈希表总是保持着每个字符最后一次出现的位置,这对于判断字符是否在当前窗口内以及决定窗口的左边界位置至关重要。

如果字符串包含如Unicode字符等其他类型的字符,算法本身并不需要做根本性的调整,因为Python的字典(哈希表)可以处理各种类型的键。然而,为了确保算法处理大范围的字符集时的性能,可能需要考虑如何有效地管理哈希表的大小和查找效率。此外,如果是在其他编程语言中实现,需要确保字符编码正确处理,并且哈希函数能够适应更广泛的字符输入。