【LeetCode #3 題解】 無重複字符的最長子串
一、題目
給定一個字符串,請你找出其中不含有重複字符的 最長子串 的長度。
- 示例 1:
輸入: "abcabcbb"
輸出: 3
解釋: 因爲無重複字符的最長子串是 "abc",所以其長度爲 3。
- 示例 2:
輸入: "bbbbb"
輸出: 1
解釋: 因爲無重複字符的最長子串是 "b",所以其長度爲 1。
- 示例 3:
輸入: "pwwkew"
輸出: 3
解釋: 因爲無重複字符的最長子串是 "wke",所以其長度爲 3。
請注意,你的答案必須是 子串 的長度,"pwke" 是一個子序列,不是子串。
二、題解一:雙指針暴力查找法 8ms 5.4M
// 暴力查找法
int lengthOfLongestSubstring(char * s){
char *begin=NULL, *end=NULL, *p=NULL;
int result=0;
begin = s; // 字串開始指針
end = s; // 字串結束指針
// 是否走到了字串最末尾
while( (*end) != '\0' ){
// 此時將當前end 字符與前面的所有字符依次匹配
p = begin;
// 當動態匹配指針走到 end 字符處時,結束前面字串匹配
while( p != end ){
// 處理當前字符與前面任意字符存在重複的情況
if( *end == *p ){
// 保存長度
if( (end-begin) > result){
result = end - begin;
}
// 將start 置於 p + 1處,重新進行下一輪匹配
begin = p+1;
break;
}
p++;
}
end++; // 開始匹配下一個字符
}
// 處理特殊情況,也就是走到末尾時,未看到重複的字符
result = result > end - begin ? result : end - begin;
return result;
}
運行結果如下:
三、驚呆:雙指針暴力查找法 優化後 4 ms ? 假的
在前面的基礎上,將 if 判斷語名修改爲三元表達式,時間從 8ms 變爲 4ms ,有點不敢相信。。。
代碼如下:
// 雙指針暴力查找法
int lengthOfLongestSubstring(char * s){
char *begin=s, *end=s, *p=NULL;
int result=0;
// 是否走到了字串最末尾
while( (*end) != '\0' ){
// 此時將當前end 字符與前面的所有字符依次匹配
p = begin;
// 當動態匹配指針走到 end 字符處時,結束前面字串匹配
while( p != end ){
// 處理當前字符與前面任意字符存在重複的情況
if( *end == *p ){
// 保存長度
result = (end-begin) > result ? end - begin : result;
// 將start 置於 p + 1處,重新進行下一輪匹配
begin = p+1;
break;
}
p++;
}
end++; // 開始匹配下一個字符
}
// 處理特殊情況,也就是走到末尾時,未看到重複的字符
result = result > end - begin ? result : end - begin;
return result;
}
這個結果確實不敢相信,我懷疑是服務器運行的差異,經過多次運行,發現確實是這樣,和三元表達式沒半毛錢關係:
3.1 優化點1:指針賦值初始化,優化0.2M 內存
雖然前面的結果有問題,但賦值初始化,經過多次實測,確實優化了內存,雖然效果不明顯。
但養成這個習慣還是好的
將代碼指針初始化賦值,實測結果優化 0.2M 內存。
修改爲:
char *begin=NULL, *end=NULL, *p=NULL;
begin = s; // 字串開始指針
end = s; // 字串結束指針
=====>
char *begin=s, *end=s, *p=NULL;
實測結果:
四、題解二:利用數組內容判定是否重複
在第一種方法中,我們使用兩個指針,
一個指針用來從字串頭走到尾,第二個指針用來再次遍歷字串判定是否重複。
因爲,本方法就是對第二個指針來進行優化,
通過數組查表法來判定是否重複,避免指針再次遍歷。
// 解法二、利用數組判定是否重複
//
#define HASH_LEN 128
int lengthOfLongestSubstring(char * s){
char *p = s;
int max_count=0, start=0;
// 定義hash 數組, ascii 最大隻有128個字符
int hash_s[HASH_LEN];
// 重置所有數組值爲 0
memset(hash_s, 0x0, sizeof(hash_s));
while(*p != '\0'){
// 通過數組中的值來判定是否重複
// 如果字母是首次出現,hash_s[x]應該爲0
// 如果讀取數組內容 > 0, 說明重複了,且其索引爲 hash_s[x] -1
// 如果讀取數組內容 < start ,則說明字母在之前,不用管
if( hash_s[ *p ] != 0 && hash_s[ *p ] >= start ){
// 更新字串大小
max_count = max_count > p-s - start ? max_count : p-s - start ;
// 更新字串起始位置爲 i+1
start = hash_s[*p];
}
// 此入之所以加 1 是避免 -1 的操作
hash_s[*p] = p-s + 1;
p++;
}
// 更新字串大小
max_count = max_count > p-s - start ? max_count : p-s - start ;
return max_count;
}
運行結果如下: