题目

给定两个字符串 s1 和 s2,写一个函数来判断 s2 是否包含 s1 的排列。

换句话说,第一个字符串的排列之一是第二个字符串的子串。

示例1:

1
2
3
输入: s1 = "ab" s2 = "eidbaooo"
输出: True
解释: s2 包含 s1 的排列之一 ("ba").

示例2:

1
2
输入: s1= "ab" s2 = "eidboaoo"
输出: False

注意:

1
2
1. 输入的字符串只包含小写字母
2. 两个字符串的长度都在 [1, 10,000] 之间

思路 1

暴力法,滑动窗口依次判定。

但是超出时间限制!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
public boolean checkInclusion(String s1, String s2) {
int len1 = s1.length();
int len2 = s2.length();
if(len2<len1)
return false;
for(int i=0; i+len1<=len2; i++){
if(checkSubString(s1, s2.substring(i, i+len1)))
return true;
}
return false;
}
private boolean checkSubString(String subS1, String subS2){
String s = new String(subS2);
for(int i=0; i<subS1.length(); i++){
if(s.indexOf(subS1.charAt(i))!=-1){
s = s.replaceFirst(String.valueOf(subS1.charAt(i)), "");
}
}

return s.isEmpty()?true:false;
}
}

时间复杂度:O((len2-len1) len1 len2 * len2)

空间复杂度:O(1)

思路 2

也是滑动窗口法,不过不用内置的函数(使用过程中存在循环遍历),而利用数组存储各个字母出现的次数,进行子串是否匹配的判定依据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Solution {
public boolean checkInclusion(String s1, String s2) {
int len1 = s1.length();
int len2 = s2.length();
if(len2<len1)
return false;
int[] temp1 = new int[26];
for(int i=0; i<len1; i++)
temp1[s1.charAt(i)-'a']++;
for(int i=0; i+len1<=len2; i++){
int[] temp2 = new int[26];
for(int j=0; j<s1.length(); j++){
temp2[s2.charAt(i+j)-'a']++;
}
if(match(temp1, temp2))
return true;
}
return false;
}
private boolean match(int[] tmp1, int[] tmp2){
for(int i=0; i<tmp1.length; i++){
if(tmp1[i]!=tmp2[i])
return false;
}
return true;
}
}

时间复杂度:O(len1 + (len2-len1) len1 26)

空间复杂度: O(1)

思路 3

基于思路2,继续进行优化。其实在滑动窗口中,每次只更新哈希表(数组)的第一个值及最后一个值,中间的不需要遍历。因此时间复杂度降低 len1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Solution {
public boolean checkInclusion(String s1, String s2) {
int len1 = s1.length();
int len2 = s2.length();
if(len2<len1)
return false;
int[] temp1 = new int[26];
int[] temp2 = new int[26];
for(int i=0; i<len1; i++){
temp1[s1.charAt(i)-'a']++;
temp2[s2.charAt(i)-'a']++;
}
if(match(temp1, temp2))
return true;
for(int i=0; i+len1<len2; i++){
temp2[s2.charAt(i+len1)-'a']++;
temp2[s2.charAt(i)-'a']--;
if(match(temp1, temp2))
return true;
}
return false;
}
private boolean match(int[] tmp1, int[] tmp2){
for(int i=0; i<tmp1.length; i++){
if(tmp1[i]!=tmp2[i])
return false;
}
return true;
}
}

时间复杂度:O(len1 + (len2-len1) * 26)

空间复杂度: O(1)

作者:LeetCode
链接:https://leetcode-cn.com/problems/permutation-in-string/solution/zi-fu-chuan-de-pai-lie-by-leetcode/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。