給定一個字符串,請你找出其中不含有重復字符的 最長子串 的長度。
示例 1:
輸入: "abcabcbb"
輸出: 3
解釋: 因為無重復字符的最長子串是 "abc",所以其長度為 3。
示例 2:
輸入: "bbbbb"
輸出: 1
解釋: 因為無重復字符的最長子串是 "b",所以其長度為 1。
示例 3:
輸入: "pwwkew"
輸出: 3
解釋: 因為無重復字符的最長子串是 "wke",所以其長度為 3。
請注意,你的答案必須是 子串 的長度,"pwke" 是一個子序列,不是子串。
class Solution { public: int lengthOfLongestSubstring(string s) { int maxlen = 0; int curlen = 0; unordered_map<char,int> charMap; for(int i = 0; i < s.size(); i++){ if(charMap.find(s[i]) == charMap.end()){ charMap[s[i]] = i+1; curlen += 1; } else{ curlen = min(i+1 - charMap[s[i]], curlen+1); charMap[s[i]] = i+1; } maxlen = maxlen < curlen ? curlen : maxlen; } return maxlen; } };
解題思路:
我是這么思考的:以 s[i] 結尾的子串跟以 s[i-1] 結尾的子串有什么關系?
假設我們已知以 s[i-1] 結尾的無重復字符最長子串的長度,那么對於以 s[i] 結尾的子串來說,無非就是兩種可能:
1. s[i] 曾出現過
2. s[i] 未曾出現過
情況1簡單啊,那就在前者長度的基礎上+1唄
情況2我們要稍微討論一下:
(1)如果 s[j] = s[k] = s[i],j < k < i,也就是說前面的子串出現過兩次 s[i] 了,那么計算以 s[i] 為結尾的最長無重復字符子串長度時,我們肯定是拿 s[i] 跟s[k] 來計算,而不會拿 s[j]。這意味着我們可以用一個hashmap存儲字符的位置,並且在每次出現重復字符的時候,更新hashmap。
(2)如果前面出現過 s[i],那我們計算長度的時候是不是直接 i - k 就好了呢?當然不是,因為 k 到 i 之間的這個子串可能還有其他字符的重復字符,比如: “abba”。
假設我們用 lastlen 和 curlen 分別記錄以 s[i-1],s[i] 結尾的最長無重復字符子串的長度
那么 curlen = min(lastlen+1, i - k)
因為如果 k 到 i 之間的子串出現重復字符了,那么 i - k 肯定大於 lastlen + 1,此時我們要用 lastlen 來計算 curlen,而不能拿 i 和 k來計算
如果k 到 i 之間的子串沒有出現重復字符,那么 i - k 會等於 lastlen + 1,所以取最小值是ok的。