题目
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例1
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例2
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例3
输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
示 例 4 \color{red}{示例4} 示例4
"abba"
思路(滑动窗口)
- 使用一个哈希表记录元素的索引。
- start表示窗口的左边,end表示窗口的右边。保持窗口里的元素不重复。
- 如果end在右移的时候,出现一个元素在哈希表中,说明它在之前出现过,如果这个重复的字符在窗口内,则将start移动到窗口内该重复的元素后一个位置。
- 每次更新完窗口,计算窗口的长度。
代码
class Solution {
public:
int lengthOfLongestSubstring(string s) {
unordered_map<char, int> map;
int start = 0, end = 0;
int res = 0;
while ( end < s.size() ) {
if ( map.count( s[end] ) > 0 && map[s[end]] >= start ) { // 如果end处的元素在窗口里重复,则将start的位置调整到第一个重复元素的后一个位置。
start = map[s[end]] + 1;
}
map[s[end]] = end; // 更新元素的索引
int cur = end - start + 1; // 计算当前窗口的长度,即无重复子序列的长度
res = max( res, cur ); // 保存较大的长度
++end;
}
return res;
}
};
用数组快一点
class Solution {
public:
int lengthOfLongestSubstring(string s) {
vector<int> ht( 128, -1 );
int start = 0, end = 0;
int res = 0;
while ( end < s.size() ) {
if ( ht[s[end]] != -1 && ht[s[end]] >= start )
start = ht[s[end]] + 1;
ht[s[end]] = end;
int cur = end - start + 1;
res = max( res, cur );
++end;
}
return res;
}
};
另一种写法,数组不保存字符的坐标,而是保存字符是否出现过
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int ht[128] = { 0 };
int res = 0;
int left = 0, right = 0;
while ( right < s.size() ) {
if ( ht[s[right]] == 0 ) { // 如果字符没出现过
ht[s[right]] = 1; // 标记出现
res = max( res, right - left + 1 ); // 计算最大值
}
else { // 出现过
while ( s[left] != s[right] ) { // 找到出现的位置
ht[s[left]] = 0; // 移出滑动窗口的复位
++left;
}
++left;
}
++right;
}
return res;
}
};