滑动窗口法
一、题源:
242. 有效的字母异位词
问题描述
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。
二、 思路:
1、映射
用 unordered_map 可以很方便的实现出现的字母及出现次数的计算。
参考代码如下
class Solution {
public:
bool isAnagram(string s, string t) {
unordered_map<char,int> map;
for(auto it = s.begin(); it != s.end(); it++) ++map[*it] ;
for(auto it = t.begin(); it != t.end(); it++) --map[*it] ;
for(auto it = map.begin(); it != map.end(); it++) if(it ->second != 0) return false ;
return true;
}
};
时间复杂度:
O
(
n
)
O(n)
O(n)
空间复杂度:
O
(
1
)
O(1)
O(1)
2、数组
数组实际上是最简单的哈希表,数组的大小就是散列表的大小,将关键字映射到数组下标的函数就是散列函数。
使用数组的好处是:
- 消耗内存空间较小
- 散列函数的计算量较小。
使用数组一般是针对数值大小有限且机制的情况。
参考代码如下
class Solution {
public:
bool isAnagram(string s, string t) {
int letters[26];
memset(letters, 0, sizeof(letters));
for(auto it = s.begin(); it != s.end(); ++it) ++letters[*it - 'a'];
for(auto it = t.begin(); it != t.end(); ++it) --letters[*it - 'a'];
for(size_t i =0; i < 26; ++i) if(letters[i]) return false;
return true;
}
};
时间复杂度:
O
(
n
)
O(n)
O(n)
空间复杂度:
O
(
1
)
O(1)
O(1)
三、相关题目及C++实现
383. 赎金信
问题描述:
给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。
如果可以,返回 true ;否则返回 false 。
magazine 中的每个字符只能在 ransomNote 中使用一次。
实现:
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
int letters[26] = {0};
for(auto it = magazine.begin(); it != magazine.end(); ++it) ++letters[*it - 'a'];
for(auto it = ransomNote.begin(); it != ransomNote.end(); ++it) --letters[*it - 'a'];
for(auto i = 0; i < 26; i++) if(letters[i] < 0) return false;
return true;
}
};
时间复杂度:
O
(
n
)
O(n)
O(n)
空间复杂度:
O
(
1
)
O(1)
O(1)
438. 找到字符串中所有字母异位词
问题描述:
给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。
异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。
实现:
class Solution {
public:
bool isEqual(int* letters)
{
for(auto i = 0;i < 26; i++) if(letters[i]) return false;
return true;
}
vector<int> findAnagrams(string s, string p) {
vector<int> result;
int letters[26] = {0};
auto headIt = s.begin(), rearIt = s.begin();
if(s.size() < p.size()) return result;
for(auto it = p.begin(); it != p.end(); ++it) ++letters[*it - 'a'];
for(; rearIt - s.begin() < p.size(); ++rearIt) --letters[*rearIt - 'a'];
for(;rearIt < s.end(); ++rearIt, ++headIt)
{
if(isEqual(letters)) result.push_back(headIt - s.begin());
--letters[*rearIt - 'a'];
++letters[*headIt - 'a'];
}
if(isEqual(letters)) result.push_back(headIt - s.begin());
return result;
}
};
时间复杂度:
O
(
n
)
O(n)
O(n)
空间复杂度:
O
(
1
)
O(1)
O(1)
做了一点优化,通过 nonZeroNum 来记录 letters数组 中的非零元素个数。
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
vector<int> result;
int letters[26] = {0};
int nonZeroNum = 0;
auto headIt = s.begin(), rearIt = s.begin();
if(s.size() < p.size()) return result;
for(auto it = p.begin(); it != p.end(); ++it) ++letters[*it - 'a'];
for(; rearIt - s.begin() < p.size(); ++rearIt) --letters[*rearIt - 'a'];
for(auto i = 0; i < 26; ++i)if(letters[i]) ++nonZeroNum;
for(;rearIt < s.end(); ++rearIt, ++headIt)
{
if(!nonZeroNum) result.push_back(headIt - s.begin());
if(letters[*headIt - 'a'] == -1) --nonZeroNum;
else if(letters[*headIt - 'a'] == 0) ++nonZeroNum;
++letters[*headIt - 'a'];
if(letters[*rearIt - 'a'] == 1) --nonZeroNum;
else if(letters[*rearIt - 'a'] == 0) ++nonZeroNum;
--letters[*rearIt - 'a'];
}
if(!nonZeroNum) result.push_back(headIt - s.begin());
return result;
}
};
时间复杂度:
O
(
n
)
O(n)
O(n)
空间复杂度:
O
(
1
)
O(1)
O(1)