题目:LCR 014
解法一:滑动窗口
使用两个长度26的int
数组,分别记录s1
和s2
子数组中各个字符出现的次数。滑动窗口每次移动后,通过Arrays.equals()
来确定数组内容是否相等。
public boolean checkInclusion(String s1, String s2) {
if (s1.length() > s2.length()) return false;
int[] arr1 = new int[26];
int[] arr2 = new int[26];
for (int i = 0; i < s1.length(); i++) {
arr1[s1.charAt(i) - 'a']++;
arr2[s2.charAt(i) - 'a']++;
}
if (Arrays.equals(arr1, arr2)) return true;
for (int i = s1.length(); i < s2.length(); i++) {
arr2[s2.charAt(i) - 'a']++;
arr2[s2.charAt(i - s1.length()) - 'a']--;
if (Arrays.equals(arr1, arr2)) return true;
}
return false;
}
注意:
-
Arrays.equals
效率低,需要一个个元素进行比较 -
变位词只会将字符位置变换,字符个数依然不变
解法二:滑动窗口优化
创建一个长度26的int数组,用来记录两个自符串中各个字符不同的个数,再维护一个diff变量用来记录两个字符串中不同字符的个数。
public boolean checkInclusion2(String s1, String s2) {
int diff = 0;
if (s1.length() > s2.length()) return false;
int[] arr = new int[26];
for (int i = 0; i < s1.length(); i++) {
arr[s1.charAt(i) - 'a']++;
arr[s2.charAt(i) - 'a']--;
}
for (int i : arr) {
if (i != 0) diff++;
}
if (diff == 0) return true;
for (int i = s1.length(); i < s2.length(); i++) {
int x = s2.charAt(i) - 'a', y = s2.charAt(i - s1.length()) - 'a';
//重点------
if (x == y) continue;
if (arr[x] == 0) diff++;
arr[x]--;
if (arr[x] == 0) diff--;
if (arr[y] == 0) diff++;
arr[y]++;
if (arr[y] == 0) diff--;
//重点------
if (diff == 0) return true;
}
return false;
}
解法三:双指针
该解法最简单,但是循环内部判断逻辑较为。首先创建两个前后指针,前指针指向子数组起始位置,后指针指向子数组结束位置。后指针向后遍历,当s2
子数组中的某个字符出现次数大于s1
中该字符出现次数,且该子数组长度还没有达到s1
的长度时,前指针向右移动,直到该字符出现次数和s1
中该字符出现相等,即arr[index] = 0
public boolean checkInclusion3(String s1, String s2) {
if (s1.length() > s2.length()) return false;
int[] arr = new int[26];
for (int i = 0; i < s1.length(); i++) {
arr[s1.charAt(i) - 'a']++;
}
int left = 0;
for (int right = 0; right < s2.length(); right++) {
int index = s2.charAt(right) - 'a';
arr[index]--;
while (arr[index] < 0) {
arr[s2.charAt(left) - 'a']++;
left++;
}
if (right - left + 1 == s1.length()) return true;
}
return false;
}