題目
網站題目鏈接
題目簡述:給出字符串s,找出s中最長的不存在重複字符的子串的長度
給出 "abcabcbb", 答案子串是 "abc", 返回長度 3
給出 "bbbbb" , 答案子串是 "b" , 返回長度 1
給出 "pwwkew" , 答案子串是 "wke", 返回長度 3
思路
區分子串和子序列
例如原始串s : abcabcbb
子序列: abbbb 、cbcb、abc 等均按原始串中字符順序選取部分字符組成,但字符之間不必相鄰
子串:abc 、cabcb等均爲連續的子序列
即子串是子序列的真子集題目說的字符沒指明單純是字母,因此需要考慮全部128個ASCII碼
動態規劃
dp[i] :以s[i]結尾的符合要求(最長的不存在重複字符)的子串長度
當 i = 0,dp[i] = 1
當 i ≥ 1,dp[i] = min( dp[i - 1] + 1,loc(s[i]) - pre_loc(s[i]) )其中 loc(s[i]) - pre_loc(s[i]) : 當前字符s[i]的位置到該字符前一次出現的位置的距離
例如,
遍歷abcabcbb,
當i = 2時,s[i] 爲 c,那麼 loc(s[i]) - pre_loc(s[i]) = 2 - (-1) = 3,pre_loc=-1表示之前沒出現過
當i = 4時,s[i] 爲 b,那麼 loc(s[i]) - pre_loc(s[i]) = 4 - 1 = 3生成記錄表用於計算 loc(char) - pre_loc(char)
二維空間vector<vector<int>> ascii_loc_list(ascii_size)
記錄每種字符在字符串中對應的所有下標
每行記錄着一種字符在字符串中出現的座標(按序從左到右)
例如,
對於abcabcbb,
其ascii_loc_list[98] = {1,4,6,7}
記錄着字符‘b’在字符串中出現的所有座標,‘b’的ASCII碼是98
代碼
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
class Solution {
public:
// 根據當前字符x處於字符串s中的座標curr_loc,從字符x的列表locs中,找出前一次出現的座標pre_loc
int find_pre_loc(vector<int> locs, int curr_loc) {
int index = 0;
for (index = 0; index < locs.size(); index++) {
if (locs[index] == curr_loc) break;
}
// 如果是當前是第一次出現則返回 -1 表示之前沒出現過
return (index - 1 < 0) ? -1 : locs[index - 1];
}
int lengthOfLongestSubstring(string s) {
int ascii_size = 128, str_size = s.length();
// 初始化記錄列表,每行記錄字符 x 在字符串 s 中出現的位置下標(從左到右)
vector<vector<int> > ascii_loc_list(ascii_size);
for (int loc = 0; loc < str_size; loc++) {
int ch = (int)s[loc];
ascii_loc_list[ch].push_back(loc);
}
//左到右掃描一次,loc[i]表示以s[i]結尾的最長不包含重複字符的子串長度
int* dp = new int[str_size];
int max_len = 0;
for (int loc = 0; loc < str_size; loc++) {
int ch = (int)s[loc];
int pre_loc = find_pre_loc(ascii_loc_list[ch], loc);
//臨界:以第一個字母結束的串長度肯定爲1
if (loc == 0) max_len = dp[loc] = 1;
else {
dp[loc] = min(dp[loc - 1] + 1, loc - pre_loc);
max_len = max(max_len, dp[loc]);
}
}
return max_len;
}
};
int main() {
Solution s;
cout << s.lengthOfLongestSubstring("abcabcbb") << endl; // abc ,3
cout << s.lengthOfLongestSubstring("bbbbb") << endl; // b ,1
cout << s.lengthOfLongestSubstring("pwwkew") << endl; // wke ,3
cout << s.lengthOfLongestSubstring("c") << endl; // c ,1
/**
* 提交後發現過不了全部樣例,才發現題目說的字符不止是26個字母,要包括所有ASCII碼!!!
* 下面是一個測試樣例的一部分..沒錯只是一部分,太長了放不下我刪了中間很多...
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
56789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ abcdefghijklmnopq
rstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!\"#$%&'()*+
,-./:;<=>?@[\\]^_`{|}~ abcdefghijklmnopqrstuvwxyzABCDEFGH
56789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ abcdefghijklmnopq
rstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!\"#$%&'()*+
,-./:;<=>?@[\\]^_`{|}~ abcdefghijklmnopqrstuvwxyzABCDEFGH
IJKLMNOPQRSTUVWXYZ0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_
`{|}~ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXY
Z0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ abcdefghijk
lmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!\"#$%
&'()*+,-./:;<=>?@[\\]^_`{|}~ abcdefghijklmnopqrstuvwxyzAB
CDEFGHIJKLMNOPQRSTUVWXYZ0123456789!\"#$%&'()*+,-./:;<=>?@
[\\]^_`{|}~ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRS
TUVWXYZ0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ abcde
fghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789
!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ abcdefghijklmnopqrstuv
wxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!\"#$%&'()*+,-./:
;<=>?@[\\]^_`{|}~ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLM
NOPQRSTUVWXYZ0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
56789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ abcdefghijklmnopq
rstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!\"#$%&'()*+
,-./:;<=>?@[\\]^_`{|}~ abcdefghijklmnopqrstuvwxyzABCDEFGH
IJKLMNOPQRSTUVWXYZ0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_
Z0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ abcdefghijk
lmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!\"#$%
&'()*+,-./:;<=>?@[\\]^_`{|}~ abcdefghijklmnopqrstuvwxyzAB"
*/
int wait;
cin >> wait;
return 0;
}