LeeCode_3. 无重复字符的最长子串(滑动窗口:map+set)

本文详细介绍了如何使用滑动窗口方法解决LeetCode上的最长无重复子串问题,并提供了两种实现思路:一种使用map记录字符下标,另一种使用set进行字符管理。通过示例解释了每一步操作。

一、介绍

1.题目描述

题目链接:https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/

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

2.测试样例

"abcabcbb"  # 3

"bbbbb" # 1

"abba"  # 2

"abbb" # 2

二、题解

1、滑动窗口map🟢

问题是找到字符串的最大不重复,由不重复想到map,用map记录字符出现的最后下标,在记录过程中计算答案

这里用到的是一种滑动窗口的思想,当遇到未出现的字符,向后扩展。当遇到已出现的字符,更新窗头下标

1.当遇到未出现的字符,长度+1

2.遇到已出现的字符,必定要判断是否调整非重复串的起始位置

  • 若上一个该字符超出起始下标,则当做遇到新字符,长度+1,起始位置不变
  • 若上一个该字符在起始下标后,将起始下标更新为上一个该字符的后一位。

3.更新ans,更新map中当前字符的下标(插入或更新)

4.重复123得到答案

以"abba"为例

  • 遇到‘a’,map[a]=0;长度=1,ans=1,起始下标0
  • 遇到‘b’,map[b]=1;长度=2,ans=2,起始下标0
  • 遇到‘b’,前一个b的下标1>起始下标0,更新起始下标=前面b的后一位=2,长度=当前下标-map[b]=2-1=1,map[b]=2
  • 遇到‘a’,前一个a的下标0<起始下标2,当做遇到新字符,更新长度=2,起始下标不变,map[a]=3
abba
num当前长度1212
ans答案长度1222
index起始下标0022
mapmap[a]=0map[b]=1map[b]=2map[a]=3
class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int n=s.size();
        if(n==0) return 0;
        // map记录<字符,下标>
        map<char,int> map;
        map[s[0]]=0;
        // ans记录总最大长度,num记录当前最大长度
        int num=1,ans=1;
        // index标记当前最大长度的起始下标
        int index=0;
        for(int i=1;i<n;i++){
            // map中已有字符
            if(map.count(s[i])){
                int t=map[s[i]];
                // 字符下标>=非重复串起始下标
                if(t>=index){
                    // 更新长度
                    num=i-t;
                }
                // 否则相当于遇到新字符
                else num++;
                // 更新起始下标
                index=max(t+1,index);
            }
            // 遇到新字符
            else num++;
            // 更新ans
            ans=max(num,ans);
            // 更新最后出现该字符的下标
            map[s[i]]=i;
        }
        return ans;
    }
};

image-20210918100652779

2、滑动窗口set🟡

继续改进滑动窗口的方法,利用set可以插入和删除字符元素。

  • 遍历字符串,循环加入非重复字符。
  • 遇到重复,如’a’,将上个a及之前的元素全部删除

以"abba"为例

  • 遇到‘a’,加入set,长度=1,ans=1
  • 遇到‘b’,加入set,长度=1,ans=2
  • 遇到‘b’,删除前面’ab’,set加入’b’,长度=1,ans=2
  • 遇到‘a’,set加入’a’,长度=2,ans=2
class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int n=s.size();
        if(n==0) return 0;
        set<char> set;
        // index记录左边界
        int index=0,ans=0;
        for(int i=0;i<n;i++){
            // 删除前面字符直到重复字符被删除
            if(i!=0) set.erase(s[i-1]);
            // 循环加入不重复字符
            while(index<n&&!set.count(s[index])){
                set.insert(s[index]);
                index++;
            }
            ans=max(ans,index-i);
        }
        return ans;
    }
};

image-20210918102457762

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值