每日leetcode:无重复字符的最长子串(python)

最初的想法是用一个字典记录读到的字符的位置,若读到重复的字符则记录当前子串长度,和当前最长子串进行比较记录,然后回到这个重复字符上一次出现的地方,重新开始读、记录。需要注意的是,读到重复字符时是回到该字符上一次出现的地方而非该字符第一次出现的地方,我在第一次编码时没有考虑到这一点,于是字典中只存储了0或1来表示该字符是否出现过,若出现过,则用x.index找到字符第一次出现的位置,结果函数一直陷入死循环。

def lengthOfLongestSubstring(s: str) -> int:
    loc = 0
    chara = {}
    maxlen = 0
    acclen = 0
    while loc < len(s):
        check = chara.get(s[loc], 0)
        if check == 0:
            chara[s[loc]] = loc + 1
            acclen = acclen + 1
            loc = loc + 1
        else:
            if acclen > maxlen:
                maxlen = acclen
            loc = chara[s[loc]]
            acclen = 0
            chara.clear()
    if acclen > maxlen:
        maxlen = acclen
    return maxlen

 

然后看到较优解法是滑动窗口,该算法的思想是将出现重复字符时从“窗口”最左侧开始删除,一直删到重复字符为止,并把重复字符删除,该算法遇到重复字符没有将遍历位置回到该字符上一次出现的地方,也就是我的解法,我的解法效率低在需要从重复字符上一次出现的地方后面紧接的一个字符开始再次遍历到重复字符目前最后一次出现的地方,这些工作是不必要的,但是有一个优点是不用逐个删除重复字符之前的字符。从本质上讲滑动窗口是从左往中间删,我的是从中间往右添加,如果不重复字符串较长,明显是滑动窗口效率较高。当然可以在此基础上将滑动窗口进行改进:不逐个删除,也不逐个添加,直接将不重复字符串进行保留,这样同样需要字典存储字符最后一次出现的位置。

下面是我的解法

def lengthOfLongestSubstring(s: str) -> int:
    loc = 0
    chara = {}
    maxlen = 0
    acclen = 0
    while loc < len(s):
        check = chara.get(s[loc], 0)
        if check == 0:
            chara[s[loc]] = loc + 1
            acclen = acclen + 1
            loc = loc + 1
        else:
            if acclen > maxlen:
                maxlen = acclen
            loc = chara[s[loc]]
            acclen = 0
            chara.clear()
    if acclen > maxlen:
        maxlen = acclen
    return maxlen

然后是优化后的滑动窗口

def lengthOfLongestSubstring(s: str) -> int:
    chara = {}
    maxlen = 0
    i = 0
    for j in range(len(s)):
        #这里用max函数而不直接用i = chara.get(s[j], 0)是为防止abcbda这种情况:读到第二个a时,保        
        #留下来的字符串会将中间的两个b保留下来,也就是说由于没有在字典中删除之前的重复字符,不能保 
        #证新检测到的重复字符就是保留下来的字符串中的,需要与保留字符串的第一个字符的位置进行比较后 
        #才能确定
        i = max(chara.get(s[j], 0), i)
        maxlen = max(maxlen, j - i + 1)
        chara[s[j]] = j + 1
    return maxlen

考虑到i只有在检测到当前位置为重复字符时才进行更新,可以加上一个判断条件进一步加快速度

def lengthOfLongestSubstring(s: str) -> int:
    chara = {}
    maxlen = 0
    i = 0
    for j in range(len(s)):
        if s[j] in chara:
            i = max(chara.get(s[j], 0), i)
        maxlen = max(maxlen, j - i + 1)
        chara[s[j]] = j + 1
    return maxlen

需要注意一点:不是说在发现重复字符时才更新最长长度,如果试图根据这点进行效率的提升需要加上很多的限制条件,反而得不偿失

### LeetCode '无重复字符长子' 的 Python 实现 此问的目标是从给定字符中找到不包含任何重复字符的长子长度。以下是基于滑动窗口算法的一种高效解决方案。 #### 方法概述 通过维护一个动态窗口来跟踪当前无重复字符的子范围,可以有效地解决该问。具体来说,利用哈希表记录每个字符近一次出现的位置,并调整窗口左边界以排除重复项。 #### 代码实现 以下是一个标准的 Python 解决方案: ```python def lengthOfLongestSubstring(s: str) -> int: char_index_map = {} # 存储字符及其新索引位置 max_length = 0 # 记录大子长度 start = 0 # 当前窗口起始位置 for i, char in enumerate(s): # 遍历字符 if char in char_index_map and char_index_map[char] >= start: # 如果发现重复字符,则更新窗口起点 start = char_index_map[char] + 1 char_index_map[char] = i # 更新或新增字符对应的索引 current_length = i - start + 1 # 当前窗口大小 max_length = max(max_length, current_length) # 更新大长度 return max_length ``` 上述代码的核心逻辑在于使用 `char_index_map` 来存储已访问过的字符以及它们后出现的位置[^1]。当遇到重复字符时,重新计算窗口的起始点并继续扩展窗口直到遍历结束[^2]。 对于输入 `"abcabcbb"`,执行过程如下: - 初始状态:`start=0`, `max_length=0` - 处理到第3个字符 `'c'` 之前未检测到重复,此时 `max_length=3` - 发现有重复字符 `'a'` 后移动窗口左侧至新位置,终返回结果为 `3`. 同样地,在处理像 `"bbbbb"` 这样的极端情况时也能正确得出答案为 `1`[^4]. #### 时间复杂度与空间复杂度分析 时间复杂度 O(n),其中 n 是字符长度;因为每个字符多被访问两次——加入和移除窗口各一次。 空间复杂度 O(min(m,n)) ,m 表示 ASCII 字符集大小 (通常固定为128), 而 n 取决于实际输入字符长度[^5]. ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值