给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
// 滑动窗口+hash
int lengthOfLongestSubstring(string s) {
// 使用滑动窗口,需要start和end两个指针,start指向当前字符前不重复字符串的起一个字符位置,end指向当前字符位置
// end移动指针后,需要先去hash_map中找是否有该字符之前的位置,没有存在之前位置的话,直接cur_len++,有存在的话,
// 需要判断当前字符位置距离之前存在位置与start位置的前后关系,如果在start左边,不需要管,如果在start右边或着刚
// 好start位置需要直接将start跳到当前字符之前位置后面的一个位置,并比较max_len和cur_len大小,max_len小则更新,
int start = 0, end = 0, cur_len = 0, max_len = 0;
unordered_map<char, int> hash_map; // 记录每一个字符出现的索引位置
while(end < s.size())
{
char cur_char = s[end];
if(hash_map.find(cur_char) != hash_map.end() && hash_map[cur_char]>= start)
{
start = hash_map[cur_char] + 1; // 更新start的位置为重复字符之前的位置后一个位置
cur_len = end - start; // 更新当前的长度,其实这里的长度不准确,下面会cur_len++,才是真正的长度
}
hash_map[cur_char] = end; // 更新当前字符的位置
end++;
cur_len++;
max_len = max(max_len, cur_len);
}
return max_len;
}
// 滑动窗口+桶
int lengthOfLongestSubstring1(string s) {
// 逻辑和上面的类似,只是考虑字符串位置使用ASCII中的中字符的数量来记录字符的位置
int start = 0, end = 0, cur_len = 0, max_len = 0;
vector<int> vect(256, -1);
while(end < s.size())
{
char cur_char = s[end];
if(vect[cur_char] > -1 && vect[cur_char] >= start)
{
start = vect[cur_char] + 1;
cur_len = end - start;
}
vect[cur_char] = end;
end++;
cur_len++;
max_len = max(max_len, cur_len);
}
return max_len;
}
// 滑动窗口+暴力法(多重循环)
int lengthOfLongestSubstring2(string s) {
int start = 0, end = 0, cur_len = 0, max_len = 0;
while(end < s.size())
{
char cur_char = s[end];
// 关注当前位置前的最长无重复子串中是否有和当前位置字符重复的情况
for(int i = start; i < end; ++i)
{
if(s[i] == cur_char)
{
start = i + 1;
cur_len = end - start;
break;
}
}
end++;
cur_len++;
max_len = max(max_len, cur_len);
}
return max_len;
}