滑動視窗問題(二)字串的排列
阿新 • • 發佈:2021-09-13
滑動視窗問題(二)字串的排列
問題描述
給你一個字串 s1
和 s2
,編寫一個函式來判斷 s2
是否包含 s1
的排列。換句話說,s1
的排列之一是 s2
的一個子串。
比如,對於輸入的 s1=adc
和 s2=dcda
,s2
包含 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; } }