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

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

示例 1:

复制代码
输入: s = "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。注意 "bca" 和 "cab" 也是正确答案。

示例 2:

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

示例 3:

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

提示:

  • 0 <= s.length <= 105
  • s 由英文字母、数字、符号和空格组成

第一其实是很懵的,很久没写字符串相关的了,本来这一个板块算是我的弱点,而且涉及到的东西也比较多,像动态规划这种。因此先问了GPT,让它给我启发,有些思维模式启发的感觉还是不错。

对算法题的模板感太重了,反而失去了思考。

先别想"该用什么算法模板",先抓住题目中的一个关键词:子串。子串是连续的,所以你实际上是在字符串上维护一段连续区间。

假设你正在从左往右读字符串,并且目前手里有一个满足条件的子串:

复制代码
abc

现在又读到一个 a

复制代码
abca

它不合法了。此时思考三个问题:

  1. 有没有必要把整个子串清空、从新 a 重新开始?
  2. 为了重新合法,应该移动子串的左端还是右端?
  3. 左端最少移动到哪里,才能排除重复的 a

你会发现,不需要全部推倒重来:

复制代码
abca
 ↓
bca

去掉旧的 a 以后,剩下的部分仍然有利用价值。

接下来尝试用纸模拟:

复制代码
pwwkew

每读入一个字符,都记录四件事:

复制代码
当前读到的字符
当前连续区间
区间是否合法
历史最大长度

关键在于始终维持一个"不重复区间"。新字符进来后:

  • 没有重复:区间可以继续扩大。
  • 出现重复:缩小区间,直到它重新合法。
  • 重新合法后:更新最大长度。

你需要维护的状态大致只有:

  • 当前区间的左边界。
  • 正在向右探索的位置。
  • 当前区间中有哪些字符,或者每个字符最近在哪里出现过。
  • 目前见过的最大长度。

根据GPT的引导和回复写了第一版代码:

python 复制代码
class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        n = len(s)
        res = 1

        left, right = 0, 1
        substr = {s[0]:0}

        while left < n and right < n:
            if s[right] not in substr:
                substr[s[right]] = right
                right += 1
                res = max(res, len(substr))
            else:
                # 出现了重复的
                index = substr[s[right]] # 取出重复的位置
                left = index + 1
                if right <= left: right = left + 1
                
                substr.clear()
                substr[s[left]] = left
        return res

能过三个简单的测试用例,但提交有 661 / 1036 个通过的测试用例

边界问题,或者说是移动问题,也就是出现重复字符的时候如何更新让它重新变回一个合法区间,给个反例你就能想明白了

输入

s ="mjvhmi"

输出

4

预期结果

5

自己想了下又修改了一版,逻辑没有问题可以通过,但是差点忘记len(s) == 0的情况了

python 复制代码
class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        # 最后一版本!!忘记了边界,注意是可以提交空字串的!!
        if not s:
            return 0
            
        n = len(s)
        res = 1

        left, right = 0, 1
        substr = {s[0]:0}

        while left < n and right < n:
            if s[right] not in substr:
                substr[s[right]] = right
                res = max(res, len(substr))
            else:
                # 出现了重复的
                index = substr[s[right]] # 取出重复的位置

                while left <= index:
                    del substr[s[left]]
                    left += 1
                left = index + 1
                substr[s[right]] = right
                
            right += 1
        return res

最后GPT给了一个简化版本

python 复制代码
class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        res = 0
        left = 0
        last_index = {}

        for right, char in enumerate(s):
            if char in last_index and last_index[char] >= left:
                # 移动左边界
                left = last_index[char] + 1
            last_index[char] = right # 更新
            res = max(res, right - left + 1)   # 相当于维护一个左边界

        return res

这里不去记录每个子串出现的位置,只维护一个字典记录每个字符最后一次出现的位置,避免删除操作,比较麻烦

是啊!res可以不用这个字典的长度去求,有字串左右两侧的Index自然可以得到字串的长度!

相关推荐
从零开始的嵌入式之旅几秒前
day31
linux·c语言·经验分享·笔记·嵌入式硬件
Horn Still Sounds13 分钟前
Linux系统编程进阶:进程回收、程序替换与多线程并发模型
linux·运维·服务器·c语言
ltl14 分钟前
rsync 协议与进程模型:generator、sender 与 receiver
linux
wuyk55514 分钟前
9.冒泡排序:像鱼缸泡泡一样的简单排序算法
开发语言·stm32·单片机·算法·排序算法
ouynagda24 分钟前
Linux 进程与线程学习笔记
linux·笔记·学习
渡我白衣1 小时前
深入理解 Transformer:Transformer 究竟是什么?
java·linux·开发语言·c++·人工智能·深度学习·transformer
无限码力2 小时前
8.26华为OD机试真题 新系统【字符串回文判断】
算法·华为od·华为od机考·华为od机试·华为od上机考试真题·华为od最新机试真题题解·华为od机试真题题库
Tisfy4 小时前
LeetCode 1927.求和游戏:抵消+看最值
java·leetcode·游戏·题解·博弈论
玖玥拾4 小时前
LeetCode 125 验证回文串
算法·leetcode
光电的一只菜鸡9 小时前
ubuntu之坑(二十)——VMware虚拟机系统无法正常进入如何处理
linux·运维·ubuntu