給定一個字符串,請你找出其中不含有重複字符的 最長子串 的長度。
示例 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;
}