詳解Leecode-03:無重複最長子串
阿新 • • 發佈:2018-12-02
1. 暴力窮舉遍歷(慢)
/**
* #3
* 無重複最長字元子串
* https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/description/
* @param s
* @return
*/
/** 方法一:暴力遍歷 **/
public int lengthOfLongestSubstring (String s){
// 獲取原始字串的長度
int n = s.length();
// 初始化為結果的長度為0
int ans = 0;
// 暴力遍歷,定義2個遊標,第一個遊標從0位置開始,2個遊標之間最短距離就是一個字元長度,那麼j就應該從i+1開始
for (int i = 0; i < n; i ++){
for (int j = i + 1; j <= n; j ++){
// 呼叫allUnique函式,allUnique函式會判斷在每一次的字元子串遍歷中,是否包含該單個字元
if (allUnique(s, i, j)) { ans = Math.max(ans, j - i);}
}
}
return ans;
}
public boolean allUnique(String s, int start, int end){
// 定義一個Set集合,儲存判斷過的字元
Set<Character> set = new HashSet<Character>();
// 在開始和結束的下標之間,遍歷下標獲取字串中的單個字元
for (int i=start; i<end; i++){
// 一邊遍歷,一邊判斷 set集合中是否已經包含當前獲得的字元,如果判斷到了包含,那麼說明字元已經開始重複
if (set.contains(s.charAt(i))){
return false;
}
set.add(s.charAt(i));
}
// 最壞的情況下,在start和end的範圍內,每個字元都不包含,那麼直接return true
return true;
}
2. 滑動視窗
/** 方法二:滑動視窗 **/
public int lengthOfLongestSubstringSlidingWindow (String s){
// 初始化定義返回結果,原始字串長度,遍歷遊標
int n = s.length(), ans = 0, i = 0, j = 0;
// 定義儲存單個字元的 HashSet(無序不重複)
Set<Character> set = new HashSet<Character>(n);
// 在 i、j都在 n的範圍內進行從左向後的遍歷
// 可以想象為有一個視窗,在一個字串上進行從左向右的滑動
// 初始狀態下,這個視窗是一個[i,j),左閉,右開的範圍
// 然後 i、j 依次開始累加,要麼左區間向右移動一格,要麼右區間向右移動一格,依次向後
// 所以最壞的情況下,每個元素都被i和j訪問2次,複雜度為 O(2n) = O(n)
while (i < n && j < n){
// 判斷視窗右端的值是否在Set中,如果不在,那麼把元素塞到Set裡,形象到視窗中就是右區間向右移動一格
if (! set.contains(s.charAt(j))){
set.add(s.charAt(j++));
ans = Math.max(ans, j - i);
} else {
//如果在,那麼刪掉左邊的元素,形象到視窗中就是左區間向右移動一格
set.remove(s.charAt(i++));
}
}
return ans;
}