【LeetCode】003——无重复字符的最长子串

本文探讨了寻找字符串中无重复字符最长子串的问题,提供了两种解决方案:一种是基于遍历和检查的O(n^2)算法,另一种是更高效的滑动窗口O(n)算法,后者使用了256位整型数组进行字符位置映射。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

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

示例 1:

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

示例 2:

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

示例 3:

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

请注意,你的答案必须是子串的长度,“pwke” 是一个子序列,不是子串

一、解法一

  • 1、先遍历整个字符串
  • 2、对遍历到的每次字符的后一个字符做判断(判断是否在遍历完的字符中出现过)
  • 3、建立一个空字符串,如果判断的字符没有出现过,则将它加入到建立的字符串中,并记录建立的字符串的长度
class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        """
        :type s: str
        :rtype: int
        """
        maxLength = 0  # 记录最长字符串长度
        for i,_ in enumerate(s):  # enumerate生成字符串迭代器,下标以及对应的字符
            count = 0  # 记录字符串长度
            newChar = str()  # 新建字符串
            for j in s[i:]:  # 遍历外轮遍历字符的后面字符
                if j not in newChar:  # 如果没有出现
                    newChar += j  # 追加到新建的字符串中
                    count += 1  # 并且长度+1
                    if maxLength < count:  # 如果最大长度小于该长度
                        maxLength = count  # 更新最长长度
                else: # 如果出现过,退出本次内轮遍历      
                    break
        return maxLength

上面代码的算法复杂度为 O(n2)O(n^2)O(n2)

缺陷:

p w w k e w
i
    j
newChar = pw
=====================================
p w w k e w
  i
    j
newChar = w 
=====================================
p w w k e w
    i
    j
newChar = w 
  • 当内轮遍历的字符出现过,跳出内轮遍历,外轮遍历i加1,此时新建字符串少了个字符p,不可能比原本的长,因此我们可以直接跳到重复元素之后开始新的循环。
class Solution:
    def lengthOfLongestSubstring(self, s):
        """
        :type s: str
        :rtype: int
        """
        start = maxLength = 0
        newChar = {}
        for index, char in enumerate(s):
            if char in newChar and start <= newChar[char]:  # 如果出现过,更新开始位置为重复元素之后的字符开始
                start = newChar[char] + 1
            else:  # 没有出现,更新最长长度
                maxLength = max(maxLength, index - start + 1)
            usedChar[char] = index
        return maxLength

时间复杂度是O(n)O(n)O(n),空间复杂度也是O(n)O(n)O(n)

二、解法二(滑动窗口)

建立一个256位大小的整型数组 freg,用来建立字符和其出现位置之间的映射。

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

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

在这里插入图片描述

1、Java代码
public class Solution {
    public int lengthOfLongestSubstring(String s) {
        int n = s.length();
        int res = 0;
        int l = 0, r = 0;
        Set<Character> set = new HashSet<>();
        while(l < n && r < n){
           if(set.contains(s.charAt(r))){
               set.remove(s.charAt(l++));
           }else{
               set.add(s.charAt(r++));
               res = Math.max(res, r - l);
           }
        }
        return res;
    }
}
2、C++代码
class Solution {
public:
    int lengthOfLongestSubstring(string s) 
    {
        int l = 0;
        int r = 0;
        int maxLength = 0;
        int usedChar[256] = { 0 };
        while (l < s.size())
        {
            if (r < s.size() && usedChar[s[r]] == 0)
            {
                usedChar[s[r++]] += 1;
            }
            else
            {
                usedChar[s[l++]] -= 1;
            }
            maxLength = max(maxLength, r - l);
        }
        return maxLength;
    }
};
3、Python代码
class Solution:
    """
    :type s: str
    :rtype: int
    """
    def lengthOfLongestSubstring(self, s):
        l = 0
        r = 0
        maxLength = 0
        s_len = len(s)
        usedChar = [0] * 256  # 通过符号表记录符号出现次数
        while l < s_len:
            if r < s_len and usedChar[ord(s[r])] == 0:
                usedChar[ord(s[r])] += 1
                r += 1
            else:
                usedChar[ord(s[l])] -= 1
                l += 1
            maxLength = max(maxLength, r - l)
        return maxLength
### LeetCode '无重复字符长子' 的 Python 实现 此问题的目标是从给定字符中找到不包含任何重复字符的长子长度。以下是基于滑动窗口算法的一种高效解决方案。 #### 方法概述 通过维护一个动态窗口来跟踪当前无重复字符的子范围,可以有效地解决该问题。具体来说,利用哈希表记录每个字符近一次出现的位置,并调整窗口左边界以排除重复项。 #### 代码实现 以下是一个标准的 Python 解决方案: ```python def lengthOfLongestSubstring(s: str) -> int: char_index_map = {} # 存储字符及其新索引位置 max_length = 0 # 记录大子长度 start = 0 # 当前窗口起始位置 for i, char in enumerate(s): # 遍历字符 if char in char_index_map and char_index_map[char] >= start: # 如果发现重复字符,则更新窗口起点 start = char_index_map[char] + 1 char_index_map[char] = i # 更新或新增字符对应的索引 current_length = i - start + 1 # 当前窗口大小 max_length = max(max_length, current_length) # 更新大长度 return max_length ``` 上述代码的核心逻辑在于使用 `char_index_map` 来存储已访问过的字符以及它们后出现的位置[^1]。当遇到重复字符时,重新计算窗口的起始点并继续扩展窗口直到遍历结束[^2]。 对于输入 `"abcabcbb"`,执行过程如下: - 初始状态:`start=0`, `max_length=0` - 处理到第3个字符 `'c'` 之前未检测到重复,此时 `max_length=3` - 发现有重复字符 `'a'` 后移动窗口左侧至新位置,终返回结果为 `3`. 同样地,在处理像 `"bbbbb"` 这样的极端情况时也能正确得出答案为 `1`[^4]. #### 时间复杂度空间复杂度分析 时间复杂度 O(n),其中 n 是字符长度;因为每个字符多被访问两次——加入和移除窗口各一次。 空间复杂度 O(min(m,n)) ,m 表示 ASCII 字符集大小 (通常固定为128), 而 n 取决于实际输入字符长度[^5]. ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值