LeetCode-无重复字符的最长子串(滑动窗口)

本文介绍了如何使用滑动窗口算法解决LeetCode中的无重复字符的最长子串问题。首先,分析了暴力解法的时间复杂度问题,然后详细阐述了滑动窗口的概念和思想,并提供了C++实现代码,通过维护一个窗口来减少重复计算,提高效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

LeetCode-无重复字符的最长子串(滑动窗口)

前言

分享一道面试高频算法题——无重复字符的最长子串。作者水平有限,有任何问题欢迎在文章下方留言交流!

关键词:滑动窗口

题目

无重复字符的最长子串

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

示例:

输入: s = "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。

力扣原题地址:https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/

思路

1、暴力解法

凭着我们朴素的想法,可以从第1个字符开始,往后每增加一个字符,判断其是否是无重复字符的,如果含有重复字符,那么就从第2个字符开始,往后每增加一个字符,判断其中是否含有重复字符,以此类推。然后记录最长无重复字符子串的长度。

在判断字符的某一个切片是否含有重复字符时,我们可以定义一个map,从头开始遍历该切片,每遍历一个字符,就在map中查询该字符是否以存在过,如果存在则含有重复子串,如果不存在则将该字符存入map中。

该方法理论上可行,但是时间复杂度很高。套了3层循环,时间复杂度大概是n的3次方,非常高。

2、滑动窗口

上述暴力破解解法中,实际上存在非常多重复的计算。

比如字符串s:”abcdcbcbb“,当我们从第1个字符开始遍历时,我们知道s[0:4]中s[2]和s[4]是重复的,那我们就没有必要再从第2个字符开始遍历了,这是无效计算。

我们可以从第3个字符开始遍历,把第一个重复字符及其前面的字符都从子串中去掉,然后继续往后推进。

这就是滑动窗口的思想。

通俗来讲,滑动窗口其实就是一个队列,比如字符串s:”abcdcbcbb“,进入这个队列(窗口)为 ”abcd“ 满足题目要求,当再进入 ”c“,队列变成了 ”acbdc“,这时候不满足题目要求。所以,我们要移动(滑动)这个队列(窗口)!

我们只要把队列中第一个重复字符及其前面的元素移出就行了,这样便又满足了题目要求,然后继续往后添加元素就行了。期间当有更长无重复字符子串长度,更新最长无重复字符子串的长度。

至于每加入一个字符时,如何判断窗口中是否存在重复字符,只需使用一个map来记录就好了。

代码实现

在此,我用C++实现一下具体代码

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        // len:字符串长度
        int len = s.size();
        // 若字符串为空,则直接返回0
        if(len == 0) return 0;
        // dic:用于记录已出现字符的map<字符,在字符串中的位置>
        unordered_map<char,int> dic;
        // l:窗口的左边界
        int l = 0;
        // temp:当前无重复字符子串长度
        int temp = 0;
        // res:最长无重复字符子串长度
        int res = 0;
        // r:窗口的右边界
        for(int r=0;r<len;r++){
            if(dic.find(s[r]) == dic.end()){
                // 若该字符还未出现过,则存入map中
                dic.insert({s[r], r});
                // 并且当前无重复字符子串长度+1
                temp ++;
            }else{
                // 若该字符已出现过
                if(dic[s[r]] < l){
                    // 如果该重复字符的位置不在当前窗口内
                    // 更新该字符最新的位置
                    dic[s[r]] = r;
                    // 当前无重复字符子串长度+1
                    temp ++;
                    // 遍历下一个字符
                    continue;
                }
                // 如果该重复字符的位置在当前窗口内
                // 更新窗口的左边界
                l = dic[s[r]] + 1;
                // 更新最长无重复字符子串的长度
                res = max(res, temp);
                // 更新当前最长无重复字符子串的长度
                temp = r - dic[s[r]];
                // 更新该字符的最新位置
                dic[s[r]] = r;
            }
        }
        // 再次更新res,以确认res是最长无重复字符子串的长度
        res = max(res, temp);
        // 返回结果
        return res;
    }
};
### 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、付费专栏及课程。

余额充值