題意很簡單,就是尋找一個字符串中連續的最長包含不同字母的子串。
其實用最樸素的方法,從當前字符開始尋找,找到以當前字符開頭的最長子串。這個方法猛一看是個n方的算法,但是要注意到由於字符數目的限制,其實這是個O(Cn)的算法,最長也不過是C長度。所以我覺得普通方法應該是能過的。
於是寫了一個,字符數目最大也不超過256所以代碼如下:
1 class Solution { 2 public: 3 int lengthOfLongestSubstring(string s) { 4 5 int res=0; 6 for(int i=0;i<s.length();i++) 7 { 8 int flag[200]; 9 memset(flag,0,sizeof(flag)); 10 int count = 0; 11 flag[s[i]-' '] = 1; 12 int tempres = 1; 13 for (int j = i + 1; j < s.length(); j++) { 14 if (flag[s[j]-' ']==0) { 15 flag[s[j]-' ']= 1; 16 tempres++; 17 } else 18 break; 19 } 20 if (tempres > res) 21 res=tempres; 22 } 23 return res; 24 } 25 };
其中空格是ASCII碼第一個實際意義字符,所以減去‘ ’
正常的O(n)方法是使用哈希表來存已經出現的字符,使用一個指針依次檢索,如果碰到已經存在的字符,則去使用第二個指針更新這個哈希表。
從原理上來具體討論雙指針這個算法,對於第一個指針指到的字母有兩種情況:
1.從來沒有使用過
當前長度加一,將這個位置和字母加入哈希表,第二個指針不動
2.已經使用過,並且有一個哈希表存這個字母的上一個位置
獲取上一個位置右側位置(+1操作),將這個位置和第二個指針比較,
(1)如果小於第二個指針,說明以當前結尾的字符串在第j個指針的地方有字母重複,忽略這個位置,繼續以j爲準
(2)如果大於第二個指針,說明以當前結尾的字符串在這個最新的位置有重複,將指針移到這個位置,計算這個長度。
這三種情況涵蓋了所有可能,並在下面的例子中有相應出現。
代碼:
此代碼來自最多discuss區最多vote的答案:https://leetcode.com/discuss/23883/11-line-simple-java-solution-o-n-with-explanation
1 public int lengthOfLongestSubstring(String s) { 2 if (s.length()==0) return 0; 3 HashMap<Character, Integer> map = new HashMap<Character, Integer>(); 4 int max=0; 5 for (int i=0, j=0; i<s.length(); ++i){ 6 if (map.containsKey(s.charAt(i))){ 7 j = Math.max(j,map.get(s.charAt(i))+1); 8 } 9 map.put(s.charAt(i),i); 10 max = Math.max(max,i-j+1); 11 } 12 return max; 13 }
例子:
對於這個字符串:abcbcda
經過初始化循環執行過程如下:
i=0; j=0; (a,0) max(0,1)=1 第一種情況
i=1; j=0; (b,1) max(1,2)=2 同上
i=2; j=0; (c,2) max(2,3)=3 同上
i=3; j=(0,1+1)=2; (b,3) max(3,2)=3 第二種第二個情況
i=4; j=(2,2+1)=3; (c,4) max(3,2)=3 同上
i=5; j=3; (d,5) max(3,3)=3 第一種情況
i=6; j=(3,1)=3; (a,6) max(3,4)=4 第二種第一個情況