请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。
示例 1:
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
提示:
s.length <= 40000
题解:
1) 使用双指针方法,在字符串上滑动;
2) 当没有遇到重复字符时,右指针右移
3) 当遇到重复字符时, 左指针移动,移动到重复字符的下一个;
即如注释中所述,
abcedfc 当遇到第二个c时,将map中的a、b擦掉,并将左指针移动到e处,那么左指针如何知道要移动到哪里呢?通过索引字典即可得知。
class Solution {
public:
int lengthOfLongestSubstring(string s) {
if(s.size()<=1) return s.size();
map<char,int> record;
int left = 0, right = 0;
int max_length = 0;
while (left < s.size()){
// 将窗口内的字符存到map中,并将right指针右移
// 当下一个字符已经在map中时,退出循环
while ((right<s.size()) && (record.count(s[right])==0)){
record[s[right]] = right;
max_length = max(max_length,right-left+1);
right++;
}
if(right==s.size())break;
//退出循环后,则表明right当前所指的字符已经在map中存在
// 1) 将已存在的字符之前的字符全部erase擦除
// 如 abcedfc 当遇到第二个c时,将ab擦掉
// 2) 将已存在的字符对应的索引更新
int pre_index = record[s[right]];
auto iter = record.begin();
while(iter!=record.end()){
if (iter->second<pre_index)
iter = record.erase(iter);
else iter++;
}
// 将left,即左指针移动到当前重复字符的下一个
left=pre_index+1;
record[s[right]]=right;
right++;
if (right==s.size()) break;
}
return max_length;
}
};