找到字符串中所有字母异位词
题目描述
给定两个字符串 s
和 p
,找到 s
中所有 p
的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。
异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。
示例 1:
输入: s = "cbaebabacd", p = "abc"
输出: [0,6]
解释:
起始索引等于 0 的子串是 "cba", 它是 "abc" 的异位词。
起始索引等于 6 的子串是 "bac", 它是 "abc" 的异位词。
示例 2:
输入: s = "abab", p = "ab"
输出: [0,1,2]
解释:
起始索引等于 0 的子串是 "ab", 它是 "ab" 的异位词。
起始索引等于 1 的子串是 "ba", 它是 "ab" 的异位词。
起始索引等于 2 的子串是 "ab", 它是 "ab" 的异位词。
提示:
1 <= s.length, p.length <= 3 * 104
s
和p
仅包含小写字母
算法原理
解决一个小问题
-
如何快速判断两个字符串是否是”异位词“
s1 = aabca
s2 = abaca
思路1:两个依次排序,双指针比较字符是否相等(缺点:时间复杂度太高
nlogn+n
)思路2:统计各字符出现的次数(利用哈希表)
解决问题
-
暴力解法
s = "cbaebabacd", p = "abc"
延申的一个小想法(优化):
-
滑动窗口+哈希表
-
left = 0, right = 0
循环
- 进窗口
hash2[in]++
- 判断
right - left + 1 > m
出窗口
hash2[out]--
- 更新结果
check(hash2, hash1)
check
hash[26]
-
优化:更新结果的判断条件
利用变量
count
来统计窗口中有效字符的个数总结:
进窗口:
- 进入后 -> 判断此时
hash2[in] <= hash1[in]
->count++
出窗口:
- 出去前 ->
hash2[out] <= hash1[out]
->count--
更新结果:
- 判断
count == m
- 进入后 -> 判断此时
-
示例代码
Java
class Solution {
public List<Integer> findAnagrams(String ss, String pp) {
List<Integer>ret = new ArrayList<Integer>();
char[]s = ss.toCharArray();
char[]p = pp.toCharArray();
// 统计字符串中 p 中每一个字符出现的次数
int[]hash1 = new int[26];
for(char ch : p) hash1[ch - 'a']++;
// 统计窗口中每一个字符出现的次数
int []hash2 = new int[26];
int m = p.length;
for(int left = 0, right = 0, count = 0; right < s.length; right++)
{
char in = s[right];
// 进窗口 + 维护 count
if(++hash2[in - 'a'] <= hash1[in - 'a'])
count ++;
// 判断
if(right - left + 1 > m)
{
// 出窗口 + 维护 count
char out = s[left++];
if(hash2[out - 'a']-- <= hash1[out - 'a'])
count--;
}
// 更新结果
if(count == m)
ret.add(left);
}
return ret;
}
}
C++
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
vector<int> ret;
int hash1[26] = {0};
for(auto ch : p) hash1[ch - 'a']++;
int hash2[26] = {0};
int m = p.size();
for(int left = 0, right = 0, count = 0; right < s.size(); right ++)
{
char in = s[right];
if(++hash2[in - 'a'] <= hash1[in -'a'])
count ++;
if(right - left + 1 > m)
{
char out = s[left++];
if(hash2[out - 'a']--<= hash1[out - 'a'])
count--;
}
if(count == m)
ret.push_back(left);
}
return ret;
}
};