題目描述:
給定一個字串,找出不含有重複字元的最長子串的長度。
示例:
給定 "abcabcbb"
,沒有重複字元的最長子串是 "abc"
,那麼長度就是3。
給定 "bbbbb"
,最長的子串就是 "b"
,長度是1。
給定 "pwwkew"
,最長子串是 "wke"
,長度是3。請注意答案必須是一個子串,"pwke"
是 子序列 而不是子串。
解題過程:
方法一:暴力版本
顯然,對於這道題我們可以像以往一樣,遍歷所有子串,對於這個方法,我相信大家都能想到,我就直接貼程式碼了。如下
//三個for暴力解決
public static int lengthOfLongestSubstring(String s) {
int max = 0;
int temp = 0;
char[] arr = new char[s.length()];
for(int i = 0; i < s.length(); i++){
arr[i] = s.charAt(i);
temp = 1;
for(int j = i + 1; j < s.length(); j++){
int flag = 0;//用來判斷s[j]是否在arr中
for(int k = i; k < i + temp; k++){
if(arr[k] == s.charAt(j)){
flag = 1;
break;
}
}
if(flag == 1){ break;//重複
} else {
arr[i+temp] = s.charAt(j);
temp++;
}
}
if(temp > max){
max = temp;
}
}
return max;
}
前面兩個for迴圈用來遍歷所有子串,第三個for迴圈用來判斷字元s.charAt(j)是否在子串中。
方法二:各種優化
優化策略1:大家想一個問題,對於第三個迴圈,我們在陣列裡查詢該陣列是否擁有某個字元,這個查詢的過程的時間複雜度是O(n),我們是否有其他什麼方法把查詢的過程的複雜度降低到O(1)?
前幾次我們都有用過hashMap來進行對映,實際上這裡一樣可以用hashMap來儲存子串,然後再判斷s.charAt(j)是否子串中,這樣我們就可以把查詢過程的複雜度降低到O(1)了。
優化策略2:假如給你一個字串:
"abcdca"
我們在遍歷子串的過程中,最開始我們從第一個元素'a'開始遍歷,當我們遍歷到'abcd'時,在繼續查詢的時候遇到'c',此時"abcd"裡面已經有'c'了,此時該子串查詢完畢。此時長度為4,繼續下一個子串的查詢。
注意:我們繼續下一個子串查詢的時候,是從第二個元素'b'開始的。可是大家想一個問題,真的有必要從第二個元素'b'開始查詢嗎?,假如我們從'b'開始的時候,遍歷到"bcd",繼續遍歷時又會再次遇到'c',此時長度為3。比上一個子串4的長度小。
實際上,我們是沒有必要從第二個元素開始查詢的。我們直接從'd'開始查詢就可以了,也就是說,如果 s[j]s[j] 在 [i, j)[i,j) 範圍內有與 j'j′ 重複的字元。我們再下一次尋找子串時,直接從j'+1的位置開始就行了。如果你不是很理解為啥會這樣的話,可以找一些元素模擬一下勒。
優化策略3:我們每次在尋找子串的時候,會把子串放進hashMap裡,假如我們要尋找下一個子串的話,理論上是需要把hashMap裡面的元素給清空,然後再用來放置新的子串的。
但實際上,是不需要這樣子的,hashMap裡面的元素是可以重複利用的。先上程式碼吧,然後我在畫圖解釋下優化策略三。如下:
//用hashMap對映
public static int lengthOfLongestSubstring2(String s) {
int max = 0;//儲存最長子串的長度
//用來記錄子串是從哪個下標開始的
int i = 0;
Map<Character, Integer> map = new HashMap<>();
for(int j = 0; j < s.length(); j++){
if(map.containsKey(s.charAt(j))){
//從第一個重複元素的後一個開始
i = Math.max(map.get(s.charAt(j))+ 1, i);
}
//j - i + 1 表示計算此時子串的長度
max = Math.max(max, j - i + 1);
map.put(s.charAt(j), j);
}
return max;
}
假設字串為"abcba",下面演示hashMap中元素的變化情況。
當j = 2。
當j = 3是,此時出現重複的字元(黃色的表示已經被代替的字元)。
當j = 4時。
j = 4時,hashMap有重複的字元a(下標為0的那個),為啥不會把i定位到下標為2的元素上?(因為它都已經遍歷到從下標我為3的那裡了,怎麼可能還會倒回去)
這種方法的時間複雜度為O(n)。
完