s1
和s2
仅包含小写字母
class Solution {
public boolean checkInclusion(String s1, String s2) {
if (s1.length() > s2.length()) {
return false;
}
int n = s1.length(), m = s2.length();
//字符串只包含小写字母,固定滑动窗口,s1的长度n=滑动窗口长度
// 统计字符串中各个字符的个数,相等则符合
//
int[] cnt1 = new int[26];
int[] cnt2 = new int[26];
for (int i = 0; i < n; ++i) {
cnt1[s1.charAt(i) - 'a']++;
cnt2[s2.charAt(i) - 'a']++;
}
if (Arrays.equals(cnt1, cnt2)) {
return true;
}
//滑动窗口每向右滑动一次,进入窗口的字符的个数增加 1,离开窗口的字符的个数减少 1
for (int i = n; i < m; ++i) {
cnt2[s2.charAt(i) - 'a']++;
cnt2[s2.charAt(i - n) - 'a']--;
if (Arrays.equals(cnt1, cnt2)) {
return true;
}
}
return false;
}
}
每次窗口滑动时,只统计了一进一出两个字符,却比较了整个 cnt1 和 cnt2 数组。
用一个变量 diff来记录 cnt1与 cnt2的不同值的个数,这样判断 cnt1和 cnt2 是否相等就转换成了判断 diff 是否为 0
class Solution {
public boolean checkInclusion(String s1, String s2) {
if (s1.length() > s2.length()) {
return false;
}
int m = s2.length(), n = s1.length();
int[] cnt = new int[26];
for (int i = 0; i < n; ++i) {
cnt[s1.charAt(i) - 'a']--;
cnt[s2.charAt(i) - 'a']++;
}
int diff = 0;
for (int v : cnt) {
if (v != 0) {
diff++;
}
}
if (diff == 0) {
return true;
}
for (int i = n; i < m; ++i) {
int x = s2.charAt(i) - 'a', y = s2.charAt(i - n) - 'a';
if (x == y) {
continue;
}
if (cnt[x] == 0) {
diff++;
}
cnt[x]++;
if (cnt[x] == 0) {
diff--;
}
if (cnt[y] == 0) {
diff++;
}
cnt[y]--;
if (cnt[y] == 0) {
diff--;
}
if (diff == 0) {
return true;
}
}
return false;
}
}
2、双指针
class Solution {
public boolean checkInclusion(String s1, String s2) {
if (s1.length() > s2.length()) {
return false;
}
int m = s2.length(), n = s1.length();
int[] cnt = new int[26];
//cnt的值均不为正,且元素值之和为 −n。
for (int i = 0; i < n; ++i) {
cnt[s1.charAt(i) - 'a']--;
}
//还可以在保证 cnt 的值不为正的情况下,去考察是否存在一个区间,其长度恰好为n
for (int left = 0, right = 0; right < m; ++right) {
int x = s2.charAt(right) - 'a';
cnt[x]++;
while (cnt[x] > 0) {
cnt[s2.charAt(left) - 'a']--;
left++;
}
if (right - left + 1 == n) {
return true;
}
}
return false;
}
}