一、介绍
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
| a | b | b | a | |
|---|---|---|---|---|
| num当前长度 | 1 | 2 | 1 | 2 |
| ans答案长度 | 1 | 2 | 2 | 2 |
| index起始下标 | 0 | 0 | 2 | 2 |
| map | map[a]=0 | map[b]=1 | map[b]=2 | map[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;
}
};

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;
}
};

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

被折叠的 条评论
为什么被折叠?



