转码刷 LeetCode 笔记[1]:3.无重复字符的最长子串(python)

题目描述

初次错解

看 B 站视频后,了解到"滑动窗口"思想,遂自己动手尝试

python 复制代码
class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        left = 0
        lenth = 0
        max_lenth = 0
        s = list(s)
        str = []
        for char in s:
            right = 0
            if char not in str:
                str.append(char)
                right += 1
                lenth = len(str)
                if lenth > max_lenth:
                    max_lenth = lenth
            else:
                str.remove(char)
                left += 1
        return max_lenth

答案分析

输入"abcabcbb",输出的是5,正确结果是3

输入"pwwkew",输出4,正确结果是3

第二次的解法

下面是 AI 根据我的解法修正的答案:

python 复制代码
class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        left = 0
        lenth = 0
        max_lenth = 0
        seen = set()
        for right in range(len(s)):
            while s[right] in seen:
                seen.remove(s[left])
                left += 1
            seen.add(s[right])
            lenth = right - left + 1
            if lenth > max_lenth:
                max_lenth = lenth

        return max_lenth

我错哪了呢?

没有真正维护滑动窗口的左边界,只是 left += 1,但 str 中并没有正确地移除所有在左边界左边的字符;
remove(char) 只会移除第一个匹配项,这会导致窗口状态不一致;

也没有用 left 来限制窗口范围,只是把它当成一个计数器。

观察我的答案和修正之后的答案,产生了几个问题:

  1. seen = set()为什么用set不用list,二者有什么区别?
  2. 为什么seen.remove(s[left])能移除所有在左边界左边的字符,而str.remove(char)不能?
  3. while s[right] in seen: 改成 for s[right] in seen: 是不是没有区别?
  4. 子串长度为什么用right - left + 1计算,而不用len(seen)计算?
  5. seen = set()seen={} 有什么区别?

下面来逐一解答

1. seen = set()为什么用 set 不用 list,二者有什么区别?

特性 set list
查找速度 O(1)(哈希表实现) O(n)(线性扫描)
是否允许重复 ❌ 不允许重复元素 ✅ 允许重复元素
是否保持顺序 ❌ 不保持插入顺序(Python 3.7+ 中 set 会保留插入顺序,但不依赖它) ✅ 保持插入顺序

2. 为什么seen.remove(s[left])能移除所有在左边界左边的字符,而str.remove(char)不能?

python 复制代码
str.remove(char)

这行代码的意思是:从 list 中删除第一个 等于 char 的元素;它不会删除所有在左边界左边的字符;它只是把第一次出现的那个字符删掉;所以窗口状态就乱了,并没有真正"滑动"窗口。

python 复制代码
while s[right] in seen:
    seen.remove(s[left])
    left += 1

通过 while 循环,可以只要出现重复字符,就删掉一次该字符,并实现左边界右移,直到窗口中没有重复子串为止。

关于循环,进而又产生了新的问题

3. while s[right] in seen: 改成 for s[right] in seen: 是不是没有区别?

有区别!

语法层面的错误

for s[right] in seen: 试图把 seen 中的每个元素赋值给 s[right],也就是试图修改原字符串 s 的内容 ------ 这是不允许的(字符串是不可变的),会报错:

TypeError: 'str' object does not support item assignment

逻辑层面的错误

for 循环会遍历 set 中的每个元素,而不是只要重复就一直删。

4. 子串长度为什么用right - left + 1计算,而不用len(seen)计算?

right - left + 1 是窗口的实际长度,也就是从 left 到 right 之间的子串长度

len(seen) 是不重复的字符数量,当把题目改为"允许最多两个重复"时,len(seen)输出的结果就不是子串长度了

只是在这道题中,这两个值相等。

5. seen = set()seen={} 有什么区别?

纯纯的基础不牢!刷题刷懵了!

seen = set()是创建一个空集合
seen={}是创建一个空字典

写法 类型 是否可哈希去重
set() set ✅ 是
{} dict ❌ 否
相关推荐
LuminousCPP3 分钟前
数据结构-双向循环链表
c语言·数据结构·笔记·链表
不爱学英文的码字机器26 分钟前
推荐算法梳理,六种主流模型与九步训练流程
算法·机器学习·推荐算法
白狐_7981 小时前
408数据结构第5章:树与二叉树②——遍历、线索树、森林与哈夫曼
数据结构·算法·深度优先
302wanger2 小时前
【阅读笔记】当AI拿走一切之后
笔记
疯狂打码的少年3 小时前
【数据结构】串(字符串):基本概念与存储
数据结构·笔记
致Great4 小时前
科研人的 AI,不该只回答问题:我用字节TraeWork 跑了一遍真实研究任务
算法
纵有疾風起4 小时前
线性表的定义与基本操作 — 从逻辑结构到 ADT 接口
数据结构·算法·408·线性表·adt
测试_AI_一辰5 小时前
AI Agent 评测最隐蔽的坑-记忆
人工智能·算法·ai·自动化·ai编程
Hotchip_MEMS5 小时前
TWS耳机微米级较量:超薄LGA封装如何助力MEMS麦克风小型化?
人工智能·笔记·物联网·电脑
lucas_AI5 小时前
给YOLO检测器插 LoRA,'插对地方'比'插什么'更要命
人工智能·算法