今日打卡,LeetCode第三题(源码详解分享)

发布于:2025-05-23 ⋅ 阅读:(17) ⋅ 点赞:(0)

Leetcode

题目:3. 无重复字符的最长子串

可以先看官方的解释,枚举所有起始下标的可能,以abcabcbb为例:

  • 以 (a)bcabcbb 开始的最长字符串为 (abc)abcbb;
  • 以 a(b)cabcbb 开始的最长字符串为 a(bca)bcbb;
  • 以 ab©abcbb 开始的最长字符串为 ab(cab)cbb;
  • 以 abc(a)bcbb 开始的最长字符串为 abc(abc)bb;
  • 以 abca(b)cbb 开始的最长字符串为 abca(bc)bb;
  • 以 abcab©bb 开始的最长字符串为 abcab(cb)b;
  • 以 abcabc(b)b 开始的最长字符串为 abcabc(b)b;
  • 以 abcabcb(b) 开始的最长字符串为 abcabcb(b)。

官方源码:

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        # 哈希集合,记录每个字符是否出现过
        occ = set()
        n = len(s)
        # 右指针,初始值为 -1,相当于我们在字符串的左边界的左侧,还没有开始移动
        rk, ans = -1, 0
        for i in range(n):
            if i != 0:
                # 左指针向右移动一格,移除一个字符
                occ.remove(s[i - 1])
            while rk + 1 < n and s[rk + 1] not in occ:
                # 不断地移动右指针
                occ.add(s[rk + 1])
                rk += 1
            # 第 i 到 rk 个字符是一个极长的无重复字符子串
            ans = max(ans, rk - i + 1)
        return ans

源码解释

  • occ = set(),是初始化了一个集合occ,用来存储当前窗口中的字符

  • n = len(s),n是字符串的长度

  • rk, ans = -1, 0,rk初始化为-1,ans初始化为0,可以理解为简单的初始化赋值

  • for i in range(n):,遍历每个字符,这里遍历的是下标,range()中的n是整型,范围长度是n,是从0开始,如果是指定起始值,例如起始值为1,range(1,n),n是闭环,range的输出不包括n,可以简单的实现下:

    for i in range(1,8):
        print(i)
    # i的结果是1、2、3、4、5、6、7
    
  • for循环里中的流程

    • ans = max(ans, rk - i + 1),比较ansrk - i + 1的值,谁最大就赋值给ans
    • i=0的时候,if i != 0:下的语句就不运行了,可以直接先不用看,观察下while rk + 1 < n and s[rk + 1] not in occ:,这里就有一个注意的点,rk的值,rk的值是初始化为-1,相当于是将s字符串的左边的边界初始化为-1,但是正序下标的没有是起始下标为-1的说法(除非是倒序),所以当i=0时,rk + 1 < n合理成为了s的边界,且s[rk + 1] not in occ这个字符串第一个元素不在集合中,while语句就成立了,occ.add(s[rk + 1]),将字符串添加至集合中,后面还有一个rk += 1,意思就是while循环遍历,所以i=0时,连续不重复的字符是abc
    • i!=0的时候,就需要看下if i != 0:的时候,注意:这时rk=3,ans=3,occ.remove(s[i - 1])移除s[0],就是移除了a这个元素,那么此时,occ里面只有b和c,两个元素,再执行while rk + 1 < n and s[rk + 1] not in occ:,第一个是成立的,第二个是不成立的,因为s[rk+1]=s[4]='b',这个b已经在集合occ中,所以可以不用看下面的循环,此时连续不重复的字符长度还是3

步骤说明

  1. 初始化变量:
    • occ:集合,存储当前窗口中的唯一字符。
    • n:字符串长度。
    • rk:右指针,初始为-1(表示尚未开始移动)。
    • ans:记录最长子串长度,初始为0。
  2. 遍历字符串(左指针移动):
    • 左指针i从0开始遍历每个字符。
    • 每次循环,若i不为0,则从集合中移除前一个字符s[i-1](左指针右移,缩小窗口左边界)。
  3. 扩展右指针:
    • 在左指针固定的情况下,尽可能向右移动右指针rk,直到遇到重复字符。
    • 将新字符加入集合occ,并更新rk
  4. 更新最大长度:
    • 每次右指针停止后,计算当前窗口长度rk - i + 1,并与ans比较取最大值。

网站公告

今日签到

点亮在社区的每一天
去签到