1. 程式人生 > >詳解Leecode-03:無重複最長子串

詳解Leecode-03:無重複最長子串

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;
    }