- 无重复字符的最长子串
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: s = “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
示例 2:
输入: s = “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
示例 3:
输入: s = “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。
示例 4:
输入: s = “”
输出: 0
提示:
0 <= s.length <= 5 * 104
s 由英文字母、数字、符号和空格组成
通过次数993,207提交次数2,673,442
解题思路: 滑动窗口
AC代码:
/*
维护一个区间的左边界和右边界
如果没有重复的元素就不断从右边放入元素
否则就从左端点不断删除元素
时间复杂度O(n)
*/
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int left=0, right=0, len=s.length(),maxlen=0;
//根据题意,256大小的整型数组足以跟踪满足要求的字符的出现次数(ASCII码值小于256)
//乱七八糟的字符不包括,计算机中的字符总共是128个,也即是ASCII码,其中33个是无法显示字符,95个是可以显示字符。
int count[256] = {0};
while(right<len){
if(count[s[right]]==0){//新字符
count[s[right]]++;
maxlen = max(maxlen, right-left+1); //只有在右边界扩展时才有可能产生新的最大长度
right++;
}
else{//找到重复字符,对左边界进行操作
//关键
count[s[left]]--;
left++;
}
}
return maxlen;
}
};
需要想明白:
若字符串为abcdefcg...
,则前面部分的最长子串为abcdef
(两个c重复),想要找到长度超过这个子串的其它子串,则一定会从第一个c之后开始找。若非如此,则同样会遇到两个c重复的情况,且由于左边界右移,长度只会更小。
想明白之后,另一个思路也随之而来:使用count数组跟踪字符出现的位置
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int left=0, right=0, len=s.length(),maxlen=0;
int count[256];
for(int i=0;i<256;i++) count[i] = -1;
while(right<len){
if(count[s[right]] == -1 || count[s[right]]<left){//新字符
count[s[right]]=right;// 记录新字符目前所在位置
maxlen = max(maxlen, right-left+1);
right++;
}
else{//找到重复字符,对左边界进行操作
left = count[s[right]]+1;
}
}
return maxlen;
}
};
但根据提交的结果来看,两者相差不大hhh~
以上方法均是使用数组来辅助判断字符是否已经出现,那么使用set集合
来代替则是一个很容易想到的思路:
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int left=0, len=s.length(),maxlen=0;
unordered_set<char> m;
for(int i=0;i<len;i++){
while(m.find(s[i]) != m.end()){//出现重复字符
m.erase(s[left]);
left++;
}
m.insert(s[i]);
maxlen=max(maxlen, i-left+1);
}
return maxlen;
}
};