题目描述:给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例1:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例2:
输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例3:
输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
示例4:
输入: s = ""
输出: 0
题解:
思路:map键值对唯一的特性,与题中子串无重复字符不谋而合,因而采用map进行存储当前子串中每个字符对应原串中的位置索引,便于计算子串长度。一旦当前遍历的字符在字串中存在(即map中出现过),则中止当前子串,开启新一轮子串并同时更新map集合。全程用len记录最长子串长度。
class Solution {
public:
int lengthOfLongestSubstring(string s) {
//空字符串返回0
if(s.length() == 0){
return 0;
}
//map集合只存放当前正在计算长度的字符串中每个字符在s中的索引位置
//不管上次
map<char, int> mp;
//初始化,字符串s中的第一个字符对应索引为0
mp[s[0]] = 0;
//记录下次子串的起始位置
int start = 0;
//int pre = start;
//记录当前子串的起始位置
int front = start;
//用来记录最长子串的长度
int len = 1;
for(int i = 1; i < s.length(); i++){//遍历字符串中的每个字符
//如果当前字符未出现在map集合中,则将该字符加入map集合
while(i < s.length() && mp.count(s[i])==0){
mp[s[i]] = i;
i++;
}
//循环结束,代表当前子串中的字符无重复,当前s[i]为重复字符,计算长度为i-start,更新len
len = (i-start) > len ? (i-start) : len;
//cout <<len << s[i] << "%";
//如果i处于最后一个位置或全部遍历结束,则退出循环
if(i >= s.length()-1){
break;
}
//更新start为重复字符的上一次出现位置的后一个位置作为下一次子串的起始位置
start = mp[s[i]] + 1;
//从当前子串的起始位置到重复字符的上一次出现位置之间的所有字符都要移出map
for(int j = front; j <= mp[s[i]]; j++){
//cout <<s[j];
mp.erase(s[j]);
//pre++;
}
//cout << endl;
//更新front位置为下次循环子串的起始位置
front = start;
//更新map中字符s[i]出现的位置
mp[s[i]] = i;
//front = pre+1;
// pre = start;
}
return len;
}
};
记N为原字符串长度
时间复杂度:O(N)
空间复杂度:O(N)