题目
思路一 滑动窗口
变位词就是字符串中每个字符出现的次数都相同,但是排列顺序不同。统计s1中每个字母出现的次数,用大小为26的vector存储。再维护一个和s1长度相同的滑动窗口,逐渐往右移动,判断该滑动窗口中每个字符出现的次数是否与s1相同,子串中每个字符出现的次数用另一个大小为26的vector存储。
代码一
class Solution {
public:
bool checkInclusion(string s1, string s2) {
int m=s1.size(),n=s2.size();
if(m>n) return false;
vector<int> hash1(26),hash2(26);
for(int i=0;i<m;i++){
hash1[s1[i]-'a']++;
hash2[s2[i]-'a']++;
}
if(hash1==hash2) return true;
for(int i=m;i<n;i++){
hash2[s2[i]-'a']++;
hash2[s2[i-m]-'a']--;
if(hash1==hash2) return true;
}
return false;
}
};
class Solution:
def checkInclusion(self, s1: str, s2: str) -> bool:
m,n=len(s1),len(s2)
if(m>n):
return False
dict1=[0]*26
dict2=[0]*26
for i in range(m):
dict1[ord(s1[i])-ord('a')]+=1
dict2[ord(s2[i])-ord('a')]+=1
if(dict1 == dict2):
return True
for i in range(m,n):
dict2[ord(s2[i])-ord('a')]+=1
dict2[ord(s2[i-m])-ord('a')]-=1
if(dict1 == dict2):
return True
return False
优化思路
每次比较都需要比较两个vector,可以简化成用一个vector存储两个字符串的差异,并用diff变量存储两个字符串出现的字符有差异的个数。
优化代码
class Solution:
def checkInclusion(self, s1: str, s2: str) -> bool:
m,n=len(s1),len(s2)
if(m>n):
return False
dict=[0]*26
diff=0
for i in range(m):
dict[ord(s1[i])-ord('a')]-=1
dict[ord(s2[i])-ord('a')]+=1
for i in range(26):
# diff += dict[i] if dict[i]>0 else -dict[i]
if(dict[i]!=0):
diff+=1
if(diff==0):
return True
for i in range(m,n):
a=ord(s2[i])-ord('a')
b=ord(s2[i-m])-ord('a')
if(a==b):
continue
if(dict[a]==0):
diff+=1
dict[a]+=1
if(dict[a]==0):
diff-=1
if(dict[b]==0):
diff+=1
dict[b]-=1
if(dict[b]==0):
diff-=1
if(diff==0):
return True
return False
思路二 双指针
和滑动窗口优化思路相似,首先遍历一遍s1,把s1中出现的字符在cnt数组中--。再遍历一遍s2,对于s2中出现的字符在cnt数组中++。如果出现cnt[x]大于0,就移动左指针,直到cnt[x]<=0。完成这些操作之后,如果right-left+1==n,那么这就是我们要找的子串。
代码二
class Solution:
def checkInclusion(self, s1: str, s2: str) -> bool:
m,n=len(s1),len(s2)
cnt=[0]*26
for i in range(m):
cnt[ord(s1[i])-ord('a')]-=1
left,right = 0,0
while(right<n):
x=ord(s2[right])-ord('a')
cnt[x]+=1
while(cnt[x]>0):
cnt[ord(s2[left])-ord('a')]-=1
left+=1
if(right-left+1 == m):
return True
right+=1
return False