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

题目描述

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

示例

  • 输入: s = "abcabcbb",输出: 3(最长无重复子串为 "abc")
  • 输入: s = "bbbbb",输出: 1(最长无重复子串为 "b")
  • 输入: s = "pwwkew",输出: 3(最长无重复子串为 "wke")

解法一:滑动窗口(长度维护法)

思路:利用哈希表记录字符最后出现的索引,通过维护「以当前字符结尾的无重复子串长度」动态调整窗口边界。

python 复制代码
class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        ans = pre = 0  # ans记录最长长度,pre记录当前子串长度
        m = {}  # 存储字符最后出现的索引
        for k, v in enumerate(s):
            pre = min(pre + 1, k - m.get(v, -1))  # 调整当前子串长度
            ans = max(ans, pre)  # 更新最长长度
            m[v] = k  # 记录当前字符的最新位置
        return ans

关键点解析

  • pre = min(pre + 1, k - m.get(v, -1))
    • 若字符未重复,子串长度+1;若重复,则收缩窗口至重复字符的下一位
    • min 操作确保窗口左边界不回退
  • 时间复杂度:O(n),每个字符仅遍历一次
  • 空间复杂度:O(m),m为字符集大小(最坏存所有不同字符)

解法二:滑动窗口(边界维护法)

思路:直接维护窗口左边界,确保窗口内无重复字符,通过「当前索引-左边界」计算窗口长度。

python 复制代码
class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        m = {}  # 存储字符最后出现的索引
        pre, ans = -1, 0  # pre为窗口左边界(不包含),ans为最长长度
        for i, v in enumerate(s):
            pre = max(pre, m.get(v, -1))  # 左边界不回退
            ans = max(ans, i - pre)  # 计算当前窗口长度
            m[v] = i  # 记录当前字符的最新位置
        return ans

关键点解析

  • pre = max(pre, m.get(v, -1))
    • 若字符重复,左边界移动至重复字符的下一位;否则保持原边界
    • max 操作确保左边界不回退
  • 窗口长度直接由 i - pre 计算,逻辑更直观
  • 时间/空间复杂度与解法一一致

两种解法对比

维度 解法一(长度维护) 解法二(边界维护)
核心变量 pre 表示当前子串长度 pre 表示窗口左边界(不包含)
边界控制 min(pre+1, k-m[v]) max(pre, m[v])
长度计算 隐式在 pre 中更新 显式通过 i-pre 计算
代码可读性 较简洁,但逻辑需要结合子串长度理解 更直观,直接对应滑动窗口模型

优化拓展

  1. 字符集限制:若已知字符集(如ASCII),可用长度256的数组替代字典,提升常数性能
  2. 边界处理:空字符串直接返回0(两解法均已自动处理)
  3. 极端测试用例
    • 全重复字符(如"aaaaa")→ 输出1
    • 无重复字符(如"abcdefg")→ 输出长度n
    • 回文字符串(如"abba")→ 输出2(子串"ab"或"ba")

总结

两解法均为滑动窗口的经典实现,通过哈希表记录字符位置实现O(n)时间复杂度。解法二通过直接维护窗口边界,代码逻辑更贴近滑动窗口的直观理解,是更推荐的实现方式。在面试中,此类解法能体现对线性时间算法和空间换时间思想的掌握。

相关推荐
roman_日积跬步-终至千里1 小时前
【机器学习】两大线性分类算法:逻辑回归与线性判别分析:找到分界线的艺术
算法·机器学习·分类
YuTaoShao1 小时前
【LeetCode 热题 100】739. 每日温度——(解法一)单调栈+从右到左
java·算法·leetcode·职场和发展
Spider_Man1 小时前
栈中藏玄机:从温度到雨水,单调栈的逆袭之路
javascript·算法·leetcode
爱吃KFC的大肥羊2 小时前
C/C++常用字符串函数
c语言·数据结构·c++·算法
im_AMBER2 小时前
Leetcode 11 java
java·算法·leetcode
丶小鱼丶2 小时前
二叉树算法之【Z字型层序遍历】
java·算法
岁忧4 小时前
(nice!!!)(LeetCode 每日一题) 2561. 重排水果 (哈希表 + 贪心)
java·c++·算法·leetcode·go·散列表
先做个垃圾出来………4 小时前
1. 两数之和
算法·leetcode·职场和发展
神器阿龙4 小时前
排序算法-冒泡排序
数据结构·算法·排序算法
C++ 老炮儿的技术栈4 小时前
在vscode 如何运行a.nut 程序(Squirrel语言)
c语言·开发语言·c++·ide·vscode·算法·编辑器