最長不含重複字元的子字串
題目:輸入一個字串,找出字串中最長的不含重複字元的子字串,計算該子字串的長度。假設字串中的字元為“a~z”,例如 arabcacfr ,最長的字串為 rabc 和 acfr ,長度為 4 。————源自《劍指0ffer》
思路:採用暴力的方法,時間複雜度高度 n^3 ,顯然是不可取的。
本題應該採用動態規劃的方法來解決,時間複雜度只需要 n ,以及一個輔助的陣列即可。
我們直接以 arabcacfr 為例子進行分析,從頭開始遍歷字串的字元。
1.第一個字元 a ,此前 a 沒有出現過,所以長度為 f(1) = 1,最長的子字串是 a ;
2.第二個字元 r ,同樣沒出現過,所以 f(1) = 2 ,最長的子字串是 ar ;
3.第三個字元 a ,因為 在第一個已經出現過了,且 在當前的最長字串 ar 中,所以現在 f(2) = 2,最長子字串更新為 ra;
4.第四個字元 b ,f(3) = 3,第五個字元 c ,f(4) = 4 ,此時最長子字串為 rabc ;
5.第六個字元 a,在我們當前的最長子字串中已經出現,所以 f(5) = 3,最長子字串更新為 bca ;
6.第七個字元c,類似上面,所以 f(6) = 2,最長子字串為 ac ;
7.第八個字元 f,沒出現過 所以 f(7) = 3,最長子字串更新為 acf
8.最後 一個字元 r,前面已經出現過,但是不在我們當前最長子字串acf 中,所以 f(8) = 4,最長子字串更新為acfr 。
分析到此結束,接下來我們如何去實現?這就需要我們用到前面說的輔助陣列 arr,我們用一個初始化的值全為負數的陣列,以字串中的字元temp 為下標進行標記,陣列的值為該字元的位置 i 。當我們遍歷到第 i 個字元,如果
arr[ temp ] 的值為負數,那麼說明這個字元還未出現過,如果 arr[ temp ] 值不為負數,那麼說明這個字元已經出現過,接下來我們要判斷這個字元是否在我們當前統計的最長子字串中。如果不在當前的子字串中,那麼 f( i) = f(i - 1)+ 1;如果在當前的最長子字串中,就像上面的第4 、 5步,我們需要重新計算當前最長子字串,也就是需要找到上一次出現該字元的位置,然後從它後面一位開始統計。具體的程式碼:
package com.hunter.Offer_Example;
import java.util.Scanner;
/**
* 最長的沒有重複的子字串
* @author luzi
*
*/
public class longestNotRepeatSubStr {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner scan = new Scanner(System.in);
while(scan.hasNext()){
String str = scan.next();
System.out.println(getLongestSubStr(str));
}
}
private static int getLongestSubStr(String str) {
// TODO Auto-generated method stub
if(str == null)
return 0;
int[] arr = new int[26];
int max = 0;
int count = 0;
for(int i = 0; i < 26; i++){
arr[i] = -1;
}
for(int i = 0; i < str.length(); i++){
if(arr[str.charAt(i) - 'a'] == -1){
arr[str.charAt(i) - 'a'] = i;
count++;
}
else
if(arr[str.charAt(i)] != -1){
//說明當前的字元str.charAt(i)上一次出現的位置在現在統計的子字串前面,,對現在的統計沒影響
if(i - arr[str.charAt(i) - 'a'] > count){
count++;
}
//當前字元上一次出現的位置在統計之中,我們需要重新統計count即當前的最長子字串
else{
count = i - arr[str.charAt(i) - 'a'];
}
//更新當前字元的位置
arr[str.charAt(i) - 'a'] = i;
}
if(count >= max)
max = count;
}
return max;
}
}
因為題目中說明 字元在 a~z 之間,所以我們只需要一個 長度為 26 的陣列,但是如果將字元擴大到所以的ASCII碼,那就需要一個長度為 127 的陣列,並且將
arr[str.charAt(i) - 'a']
改為
arr[str.charAt(i)]