力扣567:字符串的排列
给定两个字符串 s1 和 s2,写一个函数来判断 s2 是否包含 s1 的排列。
换句话说,第一个字符串的排列之一是第二个字符串的子串。
示例1:
输入: s1 = “ab” s2 = “eidbaooo”
输出: True
解释: s2 包含 s1 的排列之一 (“ba”).
思路1:暴力检测
写过一个根据输入的字符串输出其中字符的全部排列的函数。可以先生成全部的排列,然后在一个一个的对比,但是显然这种方法会非常的慢,我们可以构思简单一点的方法。
思路2:窗口+哈希表
由于只需要检测s2的子串是否是s1的某种排列,所以只需要生成记录字母频率的哈希表,只要哈希表相同,那么就说明可以生成一种排列与之匹配。再结合专题中字母哈希的方法和题目中只有小写字母的特点,可以用一个长度为26的数组作为哈希表。
思路3:窗口更新优化
比起每次窗口滑动都创建一个哈希表,我们可以在滑动的同时更新哈希表。在窗口滑动的同时,更新两端字母的频率即可。这样可以进一步优化时间复杂度。
class Solution {
public boolean checkInclusion(String s1, String s2) {
int len1 = s1.length();
int len2 = s2.length();
int[] hashS1 = toHash(s1,0,len1);
int[] hashS2 = new int[26];
for(int i=0;i+len1<=len2;i++) {
if(i == 0) {
hashS2 = toHash(s2,0,len1);
}
else {
hashS2[s2.charAt(i-1)-'a']--;
hashS2[s2.charAt(i+len1-1)-'a']++;
}
boolean flag = true;
for(int j=0;j<26;j++) {
if(hashS1[j] != hashS2[j]) flag = false;
}
if(flag) return true;
}
return false;
}
/**
* @param s 需要转变的字符串
* @param begin 子串开始的位置
* @param end 子串结束的位置的后一个位置
* @return
*/
public int[] toHash(String s, int begin, int end) {
int[] hash = new int[26];
String str = s.substring(begin, end);
for(int i=0;i<str.length();i++) {
hash[str.charAt(i) - 'a']++;
}
return hash;
}
}