567. 字符串的排列
给定两个字符串 s1
和 s2
,写一个函数来判断 s2
是否包含 s1
的排列。
换句话说,第一个字符串的排列之一是第二个字符串的子串。
示例1:
输入: s1 = “ab” s2 = “eidbaooo”
输出: True
解释: s2 包含 s1 的排列之一 (“ba”).
示例2:
输入: s1= “ab” s2 = “eidboaoo”
输出: False
注意:
- 输入的字符串只包含小写字母
- 两个字符串的长度都在 [1, 10,000] 之间
一、分析
-
判断是否包含
s1
的排列的方法:
截取s2
中某长度和s1
字符串长度相等的子串,判断两者每个字符的数量是否一致即可。 -
统计字符数量
由于字符串只包含 26 个小写字母,我们可以使用 计数排序 来统计,即创建一个长度为 26 的数组,其下标0 ~ 25
对应a ~ z
的每个字母,其值为对应字母出现的次数。 -
判断条件
先统计s1
的字符数量count1
,再依次统计s2
中与之长度相等的子串的字符数量count2
,比较两者是否相同。
二、解答
根据分析,我们可以在 O(n) 的时间复杂度完成解答。
class Solution {
public static void main(String[] args) {
System.out.println(checkInclusion("ab", "eidbaooo"));
System.out.println(checkInclusion("ab", "eidboaoo"));
}
public static boolean checkInclusion(String s1, String s2) {
if (s1 == null || s2 == null || s1.length() > s2.length()) {
return false;
}
int[] count1 = new int[26]; // s1每个字符出现的次数
int[] count2 = new int[26]; // s2每个字符出现的次数
// 1. 进行统计
for (int i = 0; i < s1.length(); i++) {
count1[s1.charAt(i) - 'a']++;
count2[s2.charAt(i) - 'a']++;
}
// 2. 滑动窗口,滑块长度始终为 s1.length()
for (int i = s1.length(); i < s2.length(); i++) {
if (isSame(count1, count2)) {
return true;
}
count2[s2.charAt(i - s1.length()) - 'a']--; // 去掉滑块当前的首个字符
count2[s2.charAt(i) - 'a']++; // 添加最新的字符到滑块中
}
return isSame(count1, count2);
}
// 有且仅当 count1 中所有值都等于 count2 中对应值时满足条件
public static boolean isSame(int[] count1, int[] count2) {
for (int i = 0; i < count1.length; i++) {
if (count1[i] != count2[i]) {
return false;
}
}
return true;
}
}
三、项目地址
https://github.com/afei-cn/LeetCode/tree/master/567.%20Permutation%20in%20String