1. 程式人生 > 其它 >滑動視窗問題(二)字串的排列

滑動視窗問題(二)字串的排列

滑動視窗問題(二)字串的排列

問題描述

​ 給你一個字串 s1s2 ,編寫一個函式來判斷 s2 是否包含 s1 的排列。換句話說,s1 的排列之一是 s2 的一個子串。

​ 比如,對於輸入的 s1=adcs2=dcdas2 包含 s1 的排列子串 cda ,因此返回 true

解決思路

  • 滑動視窗

    固定一個長度為 s1.length()的視窗陣列 window,從 s2 的開始位置開始從左向右進行滑動,只要當前滑動的視窗區間內包含了s1 的所有字母,則說明包含 s1 的排列子串

  • 雙指標

    使用一個 right 指標作為快速指標向前移動,left 作為慢指標移動。為了保證在 [left, right] 區間內的元素都是有效的,因此每遇到一個不是s1

    字串內的字元,left 就要移動到這個位置的後一位。為了確保結果的正確性,right 指標新增的重複有效字元,在 left 向右移動時必須丟棄這個重複的字元。

實現

  • 滑動視窗

    class Solution {
        private int[] map = new int[127]; // 儲存有效字元的表
        private int[] tmpMap = new int[127]; // 視窗移動過程中記錄的字元表
    
        public boolean checkInclusion(String s1, String s2) {
            if (s2.length() < s1.length()) 
                return false;
    
            final char[] s1Array = s1.toCharArray();
            final char[] s2Array = s2.toCharArray();
    
            for (char ch: s1Array)
                map[ch]++;
    
            int N = s2Array.length;
            int left = 0, right = s1Array.length - 1;
            while (right < N) {
                // 每次重新移動時都要清楚上次的視窗記錄表
                Arrays.fill(tmpMap, 0);
    
                // 統計該 [lef, right] 視窗區間內的有效字元數
                for (int i = left; i <= right; ++i)
                    tmpMap[s2Array[i]]++;
    
                if (equal(map, tmpMap)) return true;
    
                // 向右移動視窗
                right++;
                left++;
            }
    
            return false;
        }
    
        private static boolean equal(int[] map, int[] tmpMap) {
            for (int i = 0; i < map.length; ++i) {
                if (map[i] != tmpMap[i]) return false;
            }
    
            return true;
        }
    }
    
  • 雙指標

    class Solution {
        public boolean checkInclusion(String s1, String s2) {
            if (s2.length() < s1.length()) 
                return false;
    
            final char[] s1Array = s1.toCharArray();
            final char[] s2Array = s2.toCharArray();
            final int[]  map     = new int[127];
    
            for (char ch: s1Array)
                map[ch]--;// 記錄s1字元的情況
            
            final int M = s1.length();
            final int N = s2.length();
    
            for (int right = 0, left = 0; right < N; ++right) {
                char ch = s2Array[right];
                map[ch]++;
    
                // 確保當前的區間內的字元都是有效的
                while (map[ch] > 0) {
                    map[s2Array[left++]]--;
                }
    
                if (right - left + 1 == M) 
                    return true;
            }
    
            return false;
        }
    }
    

參考:https://leetcode-cn.com/problems/permutation-in-string/solution/zi-fu-chuan-de-pai-lie-by-leetcode-solut-7k7u/