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

Posted 炫云云

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了3. 无重复字符的最长子串相关的知识,希望对你有一定的参考价值。

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

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

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

输入: s = "bbbbb"
输出: 1

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

滑动窗口

维护一个滑动窗口,窗口内的都是没有重复的字符,去尽可能的扩大窗口的大小,窗口不停的向右滑动。

  1. 如果当前遍历到的字符从未出现过,那么直接扩大右边界;
  2. 如果当前遍历到的字符出现过,则缩小窗口(左指针向右移动),然后继续观察当前遍历到的字符;
  3. 重复(1)(2),直到左指针无法再移动;
  4. 维护一个结果 ans,每次用出现过的窗口大小来更新结果 ans,最后返回 ans获取结果。

关键点

  • 用一个 set() 记录出现过的字符
  • 用一个滑动窗口记录当前 左指针 l 开始的最大的不重复的字符序列
  • ans 去记录目前位置最大的长度,每次滑动窗口更新就去决定是否需要更新 ans

以字符串 abcabcbb \\texttt{abcabcbb} abcabcbb 为例,找出从每一个字符开始的,不包含重复字符的最长子串,那么其中最长的那个字符串即为答案。对于示例一中的字符串,我们列举出这些结果,其中括号中表示选中的字符以及最长的字符串:

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        # 哈希集合,记录每个字符是否出现过
        occ = set()
        n = len(s)
        # 右指针,初始值为 0,相当于我们在字符串的左边界,还没有开始移动
        r, ans = 0, 0
        for l in range(n):
            if l != 0:
                # 左指针向右移动一格,移除一个字符
                occ.remove(s[l-1])
            while r<n and s[r] not in occ:
                # 不断地移动右指针
                occ.add(s[r])
                r += 1
            # 第 l 到 r 个字符是一个极长的无重复字符子串
            ans = max(ans, r - l + 1)
        return ans

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        # 1 定义维护变量
        res, dict = 0, {}
        l =0  # 左指针
        n = len(s)
        for r in range(n):
            # 当前位置的元素个数+1
            dict[s[r]] =dict.get(s[r],0) +1
            # 每个字母都出现一次,不重复,则对结果进行更新
            if len(dict) == r-l+1:
                res = max(res,r-l+1)
            # 当窗口长度大于哈希表长度时候 (说明存在重复元素),窗口不合法
            # 缩小窗口,直到不重复
            while len(dict) < r-l+1:
                dict[s[l]] -=1
                if dict[s[l]] ==0:
                    del dict[s[l]]
                l +=1

        return res

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        # 1 定义维护变量
        res, dict = 0, {}
        l,r =0,0  # 左,右指针
        n = len(s)
        counter = 0
        while r<n:
            # 每个字母都出现一次,不重复,则对结果进行更新
            if dict.get(s[r],0) >0:
                counter +=  1 # 重复次数
            # 当前位置的元素个数+1
            dict[s[r]] =dict.get(s[r],0) +1
            # 缩小窗口,直到不重复
            while counter>0:
                if dict[s[l]]>1:
                    counter -=  1 # 重复次数
                dict[s[l]] -=1
                l +=1
            res = max(res,r-l+1)
            r+=1

        return res
'''
用双指针维护一个滑动窗口去裁减字符串子串
建立一个哈希表来跟踪重复字符的最新位置
不断移动右指针,每当遇到一个重复字符c时,在确保左指针不往反方向移动时将其移到c的下一位
移动右指针的过程中,不断维护一个最大长度值并在程序末尾处返回
'''
class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        # 特解
        if len(s) <= 1:
            return len(s)

        # 初始化左指针, 子串最大长度
        left, max_len = 0, 0

        # 创立哈希表用来跟踪每一个重复字符的位置
        # 当右指针碰到了表中的某一个重复字符c, 在确保左指针不往反方向移动时跳到s的下一位
        hashtable = {}

        # 不断移动右指针
        for right in range(len(s)):
            # cur_char表示当前字符
            cur_char = s[right]
            # 如果当前字符之前重复过(重复位置为hashtable[cur_char])
            if cur_char in hashtable:
                # 在确保左指针不往反方向移动时将左指针移到重复位置 + 1
                if hashtable[cur_char] + 1 >= left:
                    left = hashtable[cur_char] + 1
            # 更新当前字符最新重复位置为当前右指针位置
            hashtable[cur_char] = right
            # 在移动右指针的过程中,不断维护一个最大长度值
            max_len = max(max_len, right - left + 1)
        # 返回最大长度
        return max_len

参考

力扣(LeetCode) (leetcode-cn.com)

以上是关于3. 无重复字符的最长子串的主要内容,如果未能解决你的问题,请参考以下文章

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

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

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

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

Leetcode 3.无重复字符的最长子串(带图)

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