leetcode_3_无重复字符的最长子串

无重复字符的最长子串

描述

中等

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

示例:

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

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

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

解题

遍历s并借助字典记录下不同字符出现位置

当遍历到一个字符,且该字符出现在字典中时,说明出现了重复字符

此时,这两个重复字符之间的距离就是无重复字符的长度

设置左右指针left和right(滑动窗口

当left和right之间没有重复字符时,无重复最大子串长度为right-left

当出现重复时,向右移动left指针,保证left和right之间无重复元素

当有重复元素出现时

if s[right] in dic:
    left = max(dic[s[right]], left)

更新left并不是直接等于上一个重复元素的位置

例如"abcba"

当右指针扫描到第二个"b"时,left更新为指向第一个"b"

当右指针扫描到第二个"a"时,需要判断,left是否需要更新

代码中使用max就解决了这个问题

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        dic = {}
        left = -1  # 初始位置长度,用于记录上一个重复字符的位置
        res = 0
        for right in range(len(s)):
            # 当出现重复元素时,更新left
            if s[right] in dic:
                left = max(dic[s[right]], left)
            res = max(res, right - left)
            dic[s[right]] = right  # 添加/更新字符位置

        return res

或者更直观的窗口

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        window = set()
        left = 0
        res = 0		# 保存最大的长度
        cur = 0 	# 当前窗口的长度
        for right in range(len(s)):
            cur += 1
            # 从左往右删除元素,直到窗口中没有重复字符
            while s[right] in window:
                window.remove(s[left])
                left += 1
                cur -= 1
            res = max(res, cur)
            window.add(s[right])
        return res