LeetCode题解专栏:LeetCode题解
LeetCode 所有题目总结:LeetCode 所有题目总结
大部分题目C++,Python,Java的解法都有。
题目地址:Find All Anagrams in a String - LeetCode
Given a string s and a non-empty string p, find all the start indices of p’s anagrams in s.
Strings consists of lowercase English letters only and the length of both strings s and p will not be larger than 20,100.
The order of output does not matter.
Example 1:
Input:
s: "cbaebabacd" p: "abc"
Output:
[0, 6]
Explanation:
The substring with start index = 0 is "cba", which is an anagram of "abc".
The substring with start index = 6 is "bac", which is an anagram of "abc".
Example 2:
Input:
s: "abab" p: "ab"
Output:
[0, 1, 2]
Explanation:
The substring with start index = 0 is "ab", which is an anagram of "ab".
The substring with start index = 1 is "ba", which is an anagram of "ab".
The substring with start index = 2 is "ab", which is an anagram of "ab".
这道题目的意思很容易懂,就是看s的字母是否是p字符串的排列组合。如果把p字符串的所有可能都列出来,太多了,于是我想到使用counter。
Python解法如下:
from collections import Counter
class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
res = []
p_set = dict(Counter(p))
lens = len(s)
lenp = len(p)
if lens < lenp:
return res
for i in range(0, lens-lenp+1):
s_set = dict(Counter(s[i:i+lenp]))
if s_set == p_set:
res.append(i)
return res
但上面的原始的Python解法会超时,因为有很多重复的工作,使用滑动窗口来减少工作量:
from collections import Counter
class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
res = []
p_set = Counter(p)
lens = len(s)
lenp = len(p)
if lens < lenp:
return res
s_set = Counter(s[0:lenp-1])
for i in range(lenp-1, lens):
s_set[s[i]] += 1 # include a new char in the window
start = i-lenp+1
if s_set == p_set:
res.append(start)
s_set[s[start]] -= 1 # decrease the count of oldest char in the window
if s_set[s[start]] == 0:
del s_set[s[start]] # remove the count if it is 0
return res
上面的解法可以通过了,但可以更快,因为中间还是做了很多无用功,如果能快速跳过不存在的字符,可以更快。
更快的解法:
from collections import Counter
class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
res = []
pkey = set(p)
p_set = Counter(p)
lens = len(s)
lenp = len(p)
if lens < lenp:
return res
s_set = Counter(s[0:lenp-1])
i = lenp-1
while i < lens:
if s[i] not in pkey:
start = i+1
i = start+lenp-1
if i >= lens:
break
s_set = Counter(s[start:i])
continue
s_set[s[i]] += 1 # include a new char in the window
start = i-lenp+1
if s_set == p_set:
res.append(start)
# decrease the count of oldest char in the window
s_set[s[start]] -= 1
if s_set[s[start]] == 0:
del s_set[s[start]] # remove the count if it is 0
i += 1
return res
C++解法如下:
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
vector<int> pv(26,0), sv(26,0), res;
if(s.size() < p.size())
return res;
// fill pv, vector of counters for pattern string and sv, vector of counters for the sliding window
for(int i = 0; i < p.size(); ++i)
{
++pv[p[i]-'a'];
++sv[s[i]-'a'];
}
if(pv == sv)
res.push_back(0);
//here window is moving from left to right across the string.
//window size is p.size(), so s.size()-p.size() moves are made
for(int i = p.size(); i < s.size(); ++i)
{
// window extends one step to the right. counter for s[i] is incremented
++sv[s[i]-'a'];
// since we added one element to the right,
// one element to the left should be discarded.
//counter for s[i-p.size()] is decremented
--sv[s[i-p.size()]-'a'];
// if after move to the right the anagram can be composed,
// add new position of window's left point to the result
if(pv == sv) // this comparison takes O(26), i.e O(1), since both vectors are of fixed size 26. Total complexity O(n)*O(1) = O(n)
res.push_back(i-p.size()+1);
}
return res;
}
};