大数跨境
0
0

LeetCode 3.无重复字符的最长子串详细解析

LeetCode 3.无重复字符的最长子串详细解析 点点技术屋
2025-12-07
0
题目背景

2025年12月7日,LeetCode Hot 100榜单再次更新,无重复字符的最长子串(LeetCode 3)以41.3%的通过率和中等难度评级,继续稳居字符串类题目榜首。这道题不仅是字节跳动、腾讯等大厂的面试常客,更是理解滑动窗口算法的入门典范。

给定一个字符串 s,请找出其中不含有重复字符的最长子串的长度。例如输入 "abcabcbb" 时,输出应为 3(对应子串 "abc");输入 "pwwkew" 时,输出同样为 3(对应子串 "wke")。注意子串必须是连续的字符序列,这与子序列(可非连续)有本质区别。

滑动窗口算法原理

算法核心思想

滑动窗口本质是动态维护一个边界可调整的区间,通过左右指针的移动来寻找满足条件的最优解。对于本题:

  1. 窗口定义:左指针 left 和右指针 right 之间的字符组成当前子串

  2. 扩展窗口:右指针向右移动,将新字符加入窗口

  3. 收缩窗口:当新字符与窗口内已有字符重复时,左指针移动到重复字符的下一位

  4. 记录最值:每次窗口调整后计算长度,更新最大长度

如图所示,对于输入'abcabcbb',算法通过flag指针记录窗口左边界,i指针遍历字符串:当i=3(字符'a')时,flag从0移动到1;i=4(字符'b')时,flag移动到2;i=5(字符'c')时,flag移动到3;后续移动中窗口长度始终为3,最终得到最长子串长度3。

哈希表优化

为快速判断字符是否重复,我们使用哈希表(或数组)记录字符最后出现的位置。以 Python 为例:

char_map = {}  # 键:字符 值:最近出现的索引max_len = 0left = 0
for right, char in enumerate(s):    # 若字符重复且上次出现位置在窗口内,则移动左指针    if char in char_map and char_map[char] >= left:        left = char_map[char] + 1    char_map[char] = right  # 更新字符位置    current_len = right - left + 1    max_len = max(max_len, current_len)

多语言代码对比

Python 实现

def lengthOfLongestSubstring(s: str) -> int:    char_map = {}    max_len = left = 0    for right, char in enumerate(s):        if char in char_map and char_map[char] >= left:            left = char_map[char] + 1        char_map[char] = right        max_len = max(max_len, right - left + 1)    return max_len

Java 实现

public int lengthOfLongestSubstring(String s) {    int[] lastOccur = new int[128]; // ASCII字符集    Arrays.fill(lastOccur, -1);    int maxLen = 0, left = 0;
    for (int right = 0; right < s.length(); right++) {        char c = s.charAt(right);        if (lastOccur[c] >= left) {            left = lastOccur[c] + 1;        }        lastOccur[c] = right;        maxLen = Math.max(maxLen, right - left + 1);    }    return maxLen;}

Go 实现

func lengthOfLongestSubstring(s string) int {    lastOccur := make(map[rune]int)    maxLen, left := 00
    for right, c := range s {        if pos, ok := lastOccur[c]; ok && pos >= left {            left = pos + 1        }        lastOccur[c] = right        currentLen := right - left + 1        if currentLen > maxLen {            maxLen = currentLen        }    }    return maxLen}

Rust 实现

use std::collections::HashMap;
pub fn length_of_longest_substring(sString) -> i32 {    let mut last_occur = HashMap::new();    let mut max_len = 0;    let mut left = 0;
    for (right, c) in s.chars().enumerate() {        if let Some(&pos) = last_occur.get(&c) {            if pos >= left {                left = pos + 1;            }        }        last_occur.insert(c, right);        max_len = max_len.max((right - left + 1as i32);    }    max_len}

C++ 实现

int lengthOfLongestSubstring(string s) {    vector<intlast_occur(128-1);    int max_len = 0, left = 0;
    for (int right = 0; right < s.size(); right++) {        char c = s[right];        if (last_occur[c] >= left) {            left = last_occur[c] + 1;        }        last_occur[c] = right;        max_len = max(max_len, right - left + 1);    }    return max_len;}

语言特性对比

  • Python/Go/Rust 天然支持哈希表,代码简洁

  • Java/C++ 使用数组代替哈希表(ASCII字符集),空间效率更高

  • Rust 的 HashMap 和 C++ 的 vector 都提供了 O(1) 访问复杂度

复杂度分析

时间复杂度

  • 时间复杂度始终为O(n),每个字符仅被左右指针各访问一次

空间复杂度

  • 哈希表实现:O(min(m, n)),m 为字符集大小(如ASCII为128)

  • 数组实现:O(m),m 为固定字符集大小(如128或256)

边界条件处理

特殊输入场景

  1. 空字符串:直接返回 0

  2. 单字符字符串:返回 1

  3. 全重复字符:如 "bbbbb",返回 1

  4. 无重复字符:如 "abcde",返回字符串长度

关键处理代码

def lengthOfLongestSubstring(s: str) -> int:    if not s:  # 空字符串处理        return 0    # ... 主体逻辑 ...

常见错误点

  • 左指针未判断重复位置是否在当前窗口内(需 char_map[char] >= left 条件)

  • 哈希表未实时更新字符位置

  • 忽略字符串长度为 0 的边界 case

算法优化与拓展应用

优化方向

  1. 字符集优化:对于已知字符范围(如纯英文字母),可用数组代替哈希表

  2. 早期终止:当剩余字符数小于当前最大长度时可提前退出

  3. 位运算优化:对有限字符集(如小写字母)可用位掩码记录出现位置

实际应用场景

  • 网络爬虫:控制滑动窗口大小抓取连续内容

  • 日志分析:定位最长无重复ID序列

  • 编辑器实现:高亮显示重复字符区间

总结

滑动窗口算法通过动态调整区间边界,将暴力解法的 O(n²) 复杂度优化至 O(n),完美解决了无重复字符子串问题。本文提供的五种语言实现展示了不同编程范式下的实现技巧,核心都是通过哈希表记录字符位置,配合双指针维护窗口。

掌握该算法后,可进一步挑战 LeetCode 76(最小覆盖子串)、438(找到字符串中所有字母异位词)等进阶题目,这些题目均是滑动窗口思想的延伸应用。记住:复杂问题往往可以通过拆解为「动态区间」问题来高效解决

【声明】内容源于网络
0
0
点点技术屋
写自己擅长的Nginx,Linux,Redis,JVM和Golang 写自己学习的算法,运维总结 写一些散文随笔 写我最爱的大熊猫,发大熊猫的图片
内容 120
粉丝 0
点点技术屋 写自己擅长的Nginx,Linux,Redis,JVM和Golang 写自己学习的算法,运维总结 写一些散文随笔 写我最爱的大熊猫,发大熊猫的图片
总阅读18
粉丝0
内容120