字符串(滑动窗口) 3. 无重复字符的最长子串

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

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

示例:

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

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

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

思路1:切片实现滑动窗口(时间复杂度 O ( n 2 ) O(n^2) O(n2)

定义一个滑动窗口列表,遍历字符串:
若字符不在窗口中,则添加,扩展窗口;
若字符已经在窗口中,则将窗口先缩减到窗口列表中字符出现位置的下一字符处,再添加当前字符,保证窗口列表中无重复字符。

代码实现1:

class Solution(object):
    def lengthOfLongestSubstring(self, s: str) -> int:
        if not s:
            return 0

        window = []     # 滑动窗口列表
        max_length = 0  # 最长串长度

        for c in s:
            # 如果字符不在滑动窗口中,则直接扩展窗口
            if c not in window:
                window.append(c)
            # 如果字符在滑动窗口中,则
            # 1. 从窗口中移除重复字符及之前的字符串部分,新字符串即为无重复字符的字符串
            # 2. 再扩展窗口
            else:
                window = window[window.index(c) + 1:]
                window.append(c)

            # 更新最大长度
            max_length = max(len(window), max_length)

        return max_length

思路2:使用set()(时间复杂度 O ( n ) O(n) O(n)

定义一个哈希set,一个快指针,一个满慢针
遍历字符串:

  1. 如果遇到已经存在于set()中的值,说明 s[j] in hash_set,将慢指针i一边向前移动,一边删除对应元素,直至set()中没有当前遍历的值
  2. 快指针向前走,如果遇到新值,就向set()中添加
  3. 每次遍历过后都判断一下set的长度是否为最大长度

代码实现:

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        hash_set = set()
        max_len = 0
        i = 0
        for j in range(len(s)):
            while s[j] in hash_set:
                hash_set.remove(s[i])
                i += 1
            hash_set.add(s[j])
            max_len = max(len(hash_set), max_len)

        return max_len

思路3:使用哈希表优化(时间复杂度 O ( n ) O(n) O(n)

定义一个哈希表,一个快指针i,一个满慢针left
遍历字符串:

  1. 如果遇到已经存在于哈希表中的值,就取当前left和哈希表中已经出现值的索引+1最大的那个
  2. 快指针向前走,如果遇到新值,就向哈希表中添加
  3. 每次遍历过后都判断一下 快指针 - 慢指针 + 1 之间的长度是否为最大长度在这里插入图片描述

代码实现:

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        hash_map = {}
        max_len = 0
        left = 0
        for i, c in enumerate(s):
            if c in hash_map:
                left = max(left, hash_map[c] + 1)
            hash_map[c] = i
            max_len = max(i - left + 1, max_len)

        return max_len

思路4:使用哈希表优化滑动窗口(时间复杂度 O ( n ) O(n) O(n)

定义窗口左端变量 left 并设为-1,窗口长度为当前遍历到的值 - left。
使用 enumerate(s) 遍历索引及对应的字符串,使用哈希表存放映射关系,可能有三种情况:

  1. 哈希表中没有当前字符:直接向哈希表中添加映射关系,判断当前窗口长度是否大于最大长度,若是则更改最大长度为当前窗口长度;
  2. 哈希表中已经有当前字符,原有字符包含在窗口中:先将窗口左端变量left移动到原有字符位置(如图红色括号),再更改字符索引为当前索引值,即 {‘b’: 2};
  3. 哈希表中已经有当前字符,原有字符不包含在窗口中:直接向哈希表中更改映射关系(如字符a),判断当前窗口长度是否大于最大长度,若是则更改最大长度为当前窗口长度。

因为1、3操作相同,可将2作为if条件,1、3作为else条件。

在这里插入图片描述

代码实现2:

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        hash_map = {}
        max_len = 0
        left = -1
        
        for i, c in enumerate(s):
            if c in hash_map and hash_map.get(c) > left:
                left = hash_map.get(c)
                hash_map[c] = i
            else:
                hash_map[c] = i
                max_len = max(max_len, i-left)
            
        return max_len
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值