Files
interview/16-LeetCode Hot 100/无重复字符的最长子串.md
yasinshaw 4247e0700d refactor: convert all LeetCode solutions to Go-only
Changes:
- Removed all Java code implementations
- Kept only Go language solutions
- Renamed "## Go 解法" to "## 解法"
- Removed "### Go 代码要点" sections
- Cleaned up duplicate headers and empty sections
- Streamlined documentation for better readability

Updated files (9):
- 三数之和.md
- 两数相加.md
- 无重复字符的最长子串.md
- 最长回文子串.md
- 括号生成.md
- 子集.md
- 单词搜索.md
- 电话号码的字母组合.md
- 柱状图中最大的矩形.md

All 22 LeetCode Hot 100 Medium problems now use Go exclusively.
Code is cleaner, more focused, and easier to follow.

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-03-05 12:32:55 +08:00

4.8 KiB
Raw Blame History

无重复字符的最长子串 (Longest Substring Without Repeating Characters)

LeetCode 3. Medium

题目描述

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

示例 1

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

示例 2

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

示例 3

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

解题思路

核心思想

使用滑动窗口Sliding Window+ 哈希表记录字符位置。

算法流程

  1. 维护一个窗口 [left, right]
  2. 使用哈希表记录每个字符最后一次出现的位置
  3. 遍历字符串:
    • 如果当前字符在窗口内出现,移动 left 到重复字符的下一位
    • 更新哈希表和最大长度

复杂度分析

  • 时间复杂度O(n)n 为字符串长度
  • 空间复杂度O(min(m, n))m 为字符集大小

解法

func lengthOfLongestSubstring(s string) int {
    // 记录字符最后出现的位置
    charIndex := make(map[rune]int)
    maxLength := 0
    left := 0

    for right, char := range s {
        // 如果字符已存在且在窗口内,移动左边界
        if idx, ok := charIndex[char]; ok && idx >= left {
            left = idx + 1
        }

        // 更新字符位置
        charIndex[char] = right

        // 更新最大长度
        if right - left + 1 > maxLength {
            maxLength = right - left + 1
        }
    }

    return maxLength
}


图解过程

字符串: "abcabcbb"

步骤1: [a]bcabcbb
       left=0, right=0, maxLength=1

步骤2: [a,b]cabcbb
       left=0, right=1, maxLength=2

步骤3: [a,b,c]abcbb
       left=0, right=2, maxLength=3

步骤4: a[b,c,a]bcbb  (发现重复left移动)
       left=1, right=3, maxLength=3

步骤5: ab[c,a,b]cbb  (发现重复left移动)
       left=2, right=4, maxLength=3

步骤6: abc[a,b,c]bb  (发现重复left移动)
       left=3, right=5, maxLength=3

步骤7: abca[b,c,b]b  (发现重复left移动)
       left=4, right=6, maxLength=3

步骤8: abcab[c,b,b]  (发现重复left移动)
       left=5, right=7, maxLength=3

结果: maxLength = 3

进阶问题

Q1: 如何返回最长子串本身?

func longestSubstring(s string) string {
    charIndex := make(map[rune]int)
    maxLength := 0
    left := 0
    start := 0 // 记录起始位置

    for right, char := range s {
        if idx, ok := charIndex[char]; ok && idx >= left {
            left = idx + 1
        }
        charIndex[char] = right

        if right - left + 1 > maxLength {
            maxLength = right - left + 1
            start = left
        }
    }

    return s[start : start+maxLength]
}

Q2: 如果字符集有限(如只有小写字母),如何优化?

优化:使用数组代替哈希表

func lengthOfLongestSubstring(s string) int {
    charIndex := [128]int{} // ASCII 字符集
    for i := range charIndex {
        charIndex[i] = -1
    }

    maxLength := 0
    left := 0

    for right := 0; right < len(s); right++ {
        char := s[right]
        if charIndex[char] >= left {
            left = charIndex[char] + 1
        }
        charIndex[char] = right
        maxLength = max(maxLength, right-left+1)
    }

    return maxLength
}

func max(a, b int) int {
    if a > b {
        return a
    }
    return b
}

P7 加分项

深度理解

  • 滑动窗口:维护动态窗口,左边界根据重复字符调整
  • 哈希表优化:数组 vs HashMap时间/空间权衡
  • 边界处理:重复字符在窗口外的情况

实战扩展

  • 流式数据:处理超大字符串或流式输入
  • 多线程:分段计算后合并
  • 业务场景:日志去重、用户行为分析

变形题目

  1. 159. 至多包含两个不同字符的最长子串
  2. 340. 至多包含 K 个不同字符的最长子串

总结

这道题的核心是:

  1. 滑动窗口:动态调整窗口边界
  2. 哈希表:记录字符位置,快速判断重复
  3. 双指针left 和 right 指针协同移动

易错点

  • 忘记判断重复字符是否在窗口内(idx >= left
  • 更新 left 的时机
  • 数组越界(使用数组代替哈希表时)

最优解法:滑动窗口 + 哈希表,时间 O(n),空间 O(min(m, n))