力扣-438-找到字符串中所有字母异位词
异位词就是长度和组成字符和目标字符相同的字符串
第一想法是这样的
vector<int> findAnagrams(string s, string p) {
int n1 = s.size();
int n2 = p.size();
for (int i = 0; i < n1 - n2; i++) {
for (int j = i; j < i + n2; j++) {
// 判断接下来n2个字符是否覆盖了p中的出现的所有字符
}
}
}
这里是否覆盖怎么判断?用set?p中的字符可能重复吧,那就用hashset,value是字符出现的次数
每次copy一个hashset,value不为0就-1,等于0删除。结束如果hashset为空就是
但是很明显这样的时间复杂度和空间复杂度都差
而且最大长度3*104多半边界测试用例要超时,必须找到优化的方法
逐个匹配字符…
看题解是“滑动窗口”,理解一下
题解方法一的巧妙之处在于:
- 把字符比较转为了ASCII码数字
- 把逐个字符的相等比较转换为了词频数组的写相等比较
vector<int> findAnagrams(string s, string p) {
int sLen = s.size(), pLen = p.size();
if (sLen < pLen) return {};
vector<int> ans, sCount(26), pCount(26);
// 这里只统计了p长度的s词频
for (int i = 0; i < pLen; i++) {
++sCount[s[i] - 'a'];
++pCount[s[i] - 'a'];
}
// 通过直接判断数组巧妙地避免了挨个判断字符
if (sCount == pCount) ans.push_back(0);
for (int i = 0; i < sLen - pLen; i++) {
// 通过删除新增一个词频来实现滑动窗口
--sCount[s[i] - 'a'];
++sCount[s[i + pLen] - 'a'];
if (sCount == pCount) ans.push_back(i + 1);
}
return ans;
}
方法二则是更进一步,将逐个字符相等比较转为了所有字符的ASCII码值和相等
之所以这题能用“滑动窗口”也是基于了ASCII码
但是这里不能是简单的ASCII码加和,因为可能出现字符不一致但是ASCII码和一致的情况