LeetCode 3. Longest Substring Without Repeating Characters 給定一個字串,找到它的沒有重複字元的最大子串
Given a string, find the length of the longest substring without repeating characters.
Examples:
Given "abcabcbb"
, the answer is "abc"
, which the length is 3.
Given "bbbbb"
, the answer is "b"
, with the length of 1.
Given "pwwkew"
, the answer is "wke"
, with the length of 3. Note that the answer must be a substring
"pwke"
is a subsequence and not a substring.
Instead of using a set to tell if a character exists or not, we could define a mapping of the characters to its index. Then we can skip the characters immediately when we found a repeated character.
The reason is that if s[j]s[j] have a duplicate in the range [i, j)[i,j) with index j'j′, we don't need to increase ii little by little. We can skip all the elements in the range [i, j'][i,j′] and let ii to be j' + 1j′+1 directly.
If we know that the charset is rather small, we can replace the Map
with an integer array as direct access table.
Commonly used tables are:
int[26]
for Letters 'a' - 'z' or 'A' - 'Z'int[128]
for ASCIIint[256]
for Extended ASCII
int lengthOfLongestSubstring(string s) { int start = 0,length = 0,len=s.size(); std::vector<int> flag(256,-1);//帶位掩碼記錄每個字母的最後位置 for(int i=0;i!=len;++i){ if(flag[s[i]]>=start){ //i處的字元第二次出現時就更新最大長度和start的位置 length = std::max(length,i-start); start = flag[s[i]]+1; } flag[s[i]] = i; } return std::max(length,len-start); //如果直接返回length,則遇到輸入s為空字元或者沒有重複字元的字串時會返回0 }
int lengthOfLongestSubstring(string s) {
int n = s.length();
int i = 0, j = 0;
bool exist[256] = { false };
int max_length = 0, cur_length = 0;
while (j < n) {
if (!exist[s[j]]) {
exist[s[j]] = true;
++j;
}
else {
max_length = max(max_length, j - i);
while (s[i] != s[j]) {
exist[s[i]] = false;
++i;
}
++i;
++j;
}
}
return max(max_length, n - i);
}
這個解答的時間複雜度是O(N)。雖然有兩個while的巢狀,但是時間複雜度依然是O(N),為什麼呢?
因為i和j都只把這個string從開始到結束遍歷了一遍。
可以這樣想,外層while在改變j的值,j最多從0改變到n(n為字串的長度),內層while在改變i的值,同樣的,i最多從0改變到n(n為字串的長度)。所以加起來,時間複雜度為O(2*N),也就是O(N)。
還可以這樣想,內層迴圈不一定要進行的,僅僅當j遇到了重複字元後需要更新i的值時,才會進行記憶體迴圈,而且i加起來走過的步數最多為n(n為字串的長度)。
這段程式碼還有很有意思的一點,就是別忘了在迴圈體之外,返回值為max(max_length, n-i)。這是為什麼呢? 因為可能最後一次檢查的時候,j知道走到字串末尾都沒有遇到重複字元。而while迴圈體中找到的最長不重複子串只是在j遇到重複字元時才進行的。