—— write for my baby, mua
[題目]
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.
[中文翻譯]
給定一個字符串,求沒有重複字母的最長子串的長度。
例子:
給定 "abcabcbb",最長子串爲 "abc",長度爲3。
給定 "bbbbb",最長子串爲 "b",長度爲1。
給定 "pwwkew",最長子串爲
"wke",長度爲3。注意,結果必須爲子串,"pwke"是一個子序列而不是子串。
[解題思路]
O(N)
設字符串S下標i處的字母S[i]=A,那麼以S[i]作結尾的沒有重複字母的最長子串,受兩個因素影響。
1. S[i]=A,A上一次出現的位置a
2. 所有已經出現的重複的字母對···B···B···、···C···C···、···,第一個字母中離S[i]最近的一個的位置,即max(B,C,···)=b
第一條很自然,因爲出現了重複的A,那麼子串最長只能是[a+1,i]。
第二條的原因是,子串[a+1,i]中,可能已經出現過重複的字母,而影響最長子串的,是所有已經出現的重複字母對中,第一個字母離S[i]最近的位置b,顯然子串最長只能是[b+1,i]
綜合1、2,沒有重複字母的最長子串,只能是在[a+1,i]和[b+1,i]中取短的。
線性地遍歷整個字符串,可以用一個數組int prePosition[128]記錄每個字母上一次出現的位置,初始值設爲-1,用一個整數int startBound記錄最近出現重複字母對中第一個字母的位置,初始值設爲-1。
在考慮S[i]作結尾的最長子串時,長度即爲min(i-prePosition[S[i]], i-startBound)
考慮完S[i],如果prePosition[S[i]]>startBound,則更新startBound,因爲出現了位置更近的重複的字母對中的第一個字母;然後再更新prePosition[S[i]]=i,因爲在考慮S[i+1]時,上一次出現S[i]的位置已經變爲了i。
[C++代碼]
class Solution {
public:
int prePosition[128];
void initPrePosition() {
for (int i = 0; i < 128; i++)
prePosition[i] = -1;
}
int lengthOfLongestSubstring(string s) {
int max = 0;
int startBound = -1;
initPrePosition();
for (int i = 0; i < s.length(); i++) {
int prePos = prePosition[(int)s.at(i)];
int len;
if (prePos > startBound)
len = i - prePos;
else
len = i - startBound;
if (len > max)
max = len;
if (prePos > startBound)
startBound = prePos;
prePosition[(int)s.at(i)] = i;
}
return max;
}
};