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

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

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;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值