題目描述:算法
對於一個字符串,請設計一個高效算法,找到字符串的最長無重複字符的子串長度。ide
給定一個字符串A及它的長度n,請返回它的最長無重複字符子串長度。保證A中字符所有爲小寫英文字符,且長度小於等於500。函數
測試樣例:測試
"abcdbefgdchi",12
返回:8
這個題我研究了好半天,確實很差想,看了別人的思路,半天才把代碼寫出來spa
分析:設計
首先定義三個輔助變量:orm
max_len:表示字符串中最長無重複字符的子串長度,也就是函數返回值blog
map<char, int>:用來存放當字符串前位置的字符最近出現的位置字符串
pre_len:用來存放當前位置以前最長無重複字符的子串長度string
下面開始主邏輯
從字符串的起始處開始遍歷
若是map中沒有該字符,則將該字符及其下標插入到map中,並將pre_len++
再和max_len進行比較,取較大者賦給max_len
若是map中已經有了該字符,那麼取出該字符對應的值(也就是該字符最近出現的下標)記爲pos_A
當前下標減去pre_len記爲pos_B,表示前面最長無重複字符子串的起始位置
這時候,pos_A和pos_B會有一下三種狀況:
第一種狀況:posA == pos_B
第二種狀況:pos_A > pos_B
第三種狀況:pos_A < pos_B
對於第一種狀況來講,pre_len 大小不會改變。
對於第二種狀況來講,pos_A 在 pos_B的右邊,根據 pos_A 和 pos_B 所表明的含義可知道:
在距離當前很近的位置上,當前字符已經出現了重複,所以當前位置以前最長無重複字符子串的長度縮短了,如圖所示:
所以,更新後的 pre_len 應該爲 當前位置的下標減去 pos_A
對於第三種狀況來講,pos_A 在 pos_B 的左邊,根據 pos_A 和 pos_B 所表明的含義可知道:
在距離當前很遠的位置上,當前字符出現了重複,這個位置比pos_B 還遠,這麼遠的路徑上,pos_B 處的字符早已出現了重複,所以當前位置以前最長無重複字符子串的長度應該爲 當前位置到pos_A 的距離,如圖所示
所以,更新後的 pre_len 應該爲 當前位置的下標減去 pos_B + 1
更新後的pre_len 與max_len 進行比較,取其大者便可
注意,最後應該將map中當前位置字符的下標進行更新(千萬不能漏掉)
因而乎一個完整的邏輯已經完成了,這樣從頭至尾遍歷這個字符串,最終即可獲得
字符串的最長無重複字符的子串長度 max_len
甚至還能夠得到該字串,將其單獨打印出來(這裏留給讀者自行實現,不難)
代碼以下:
int longestSubstring(string A, int n) { if (A.size() <= 0 || n <= 0) return 0; int max_len = -1; int pre_len = 0; map<char, int> m; for (int i = 0; i < A.size(); ++i){ if (m.count(A[i]) == 0){ m.insert(pair<char, int>(A[i], i)); //map中不存在該字符,則直接插入 ++pre_len; if (pre_len > max_len) max_len = pre_len; continue; } map<char, int>::iterator iter_prev = m.find(A[i]); int pos_A = iter_prev->second; int pos_B = i - pre_len; if (pos_A > pos_B) { pre_len = i - pos_A; } else if (pos_B > pos_A) //pos_A <= pos_B { pre_len = i - pos_B + 1; } else { //do nothing! } if (pre_len > max_len) max_len = pre_len; m[A[i]] = i; //更新map } return max_len; }
如今是 2016.9.3/1:30 時候不早了,睡覺了,晚安!