Closed azl397985856 closed 2 years ago
class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
res = []
if len(s) < len(p):
return res
counter = defaultdict(int)
for char in p:
counter[char] += 1
valid_count = 0
left = 0
for right in range(len(s)):
char = s[right]
if char in counter:
counter[char] -= 1
if counter[char] >= 0:
valid_count += 1
while valid_count == len(p):
if right - left + 1 == len(p):
res.append(left)
temp = s[left]
if temp in counter:
counter[temp] += 1
if counter[temp] > 0:
valid_count -= 1
left += 1
return res
class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
np, ns = len(p), len(s)
if np > ns:
return []
pCounter, sCounter = {},{}
for i in range(np):
pCounter[p[i]] = 1 + pCounter.get(p[i],0)
sCounter[s[i]] = 1 + sCounter.get(s[i],0)
res = [0] if sCounter == pCounter else []
l = 0
for r in range(np, ns):
sCounter[s[r]] = 1 + sCounter.get(s[r],0)
sCounter[s[l]] -= 1
if sCounter[s[l]] <= 0:
sCounter.pop(s[l])
l += 1
if sCounter == pCounter:
res.append(l)
return res
class Solution(object):
def findAnagrams(self, s, p):
"""
:type s: str
:type p: str
:rtype: List[int]
"""
if len(s) < len(p):
return []
pcount = collections.Counter(p)
scount = collections.Counter()
ans = []
for i in range(len(s)):
scount[s[i]] += 1
if i >= len(p):
if scount[s[i-len(p)]] == 1:
del scount[s[i-len(p)]]
else:
scount[s[i-len(p)]] -= 1
if pcount == scount:
ans.append(i-len(p)+1)
return ans
O(n)
// 使用hashmap来存储每个letter的个数,使用sliding window来更新hashmap
// 当 ptr2 - ptr1 >= anagram.size() 时候,更新ptr1,也就是window的左边的自增
// 当 ptr2 也就是window的右边 >= anagram.size() - 1时,检查两个hashmap
// 使用std::unordered_map会比使用std::vector<int>(26,0)慢很多(100倍时间),而且还要额外写compare unordered_map的函数
// Time: O(n)
// Space: O(1) or O(26)
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
std::vector<int> map(26,0);
std::vector<int> anagram_map(26,0);
for (auto& c: p) {
anagram_map[c-'a']++;
}
std::vector<int> results;
int anagram_size = p.size();
int start = 0;
for (int i = 0; i < s.size(); i++) {
map[s[i]-'a']++;
if (i - start >= anagram_size) {
map[s[start++]-'a']--;
}
if (i >= anagram_size - 1) {
if (map == anagram_map) {
results.push_back(start);
}
}
}
return results;
}
};
class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
if len(s) < len(p):
return []
result = []
p_dict = Counter(p)
s_dict = defaultdict(int)
for idx in range(len(p)):
s_dict[s[idx]] += 1
if s_dict == p_dict:
result.append(0)
left = 0
for right in range(len(p), len(s)):
s_dict[s[right]] += 1
s_dict[s[left]] -= 1
if s_dict[s[left]] == 0:
del s_dict[s[left]]
left += 1
if s_dict == p_dict:
result.append(left)
return result
时间复杂度:O(n) 空间复杂度:O(n)
滑动窗口
Code
class Solution { public List<Integer> findAnagrams(String s, String p) { // List that stores results List<Integer> res = new ArrayList<>(); if (p.length() > s.length()) { return res; } // Impossible case
// Use Array to store target string info: Char & Frequency
int[] target = new int[26];
for (int i = 0; i < p.length(); i++) {
target[p.charAt(i) - 'a']++;
}
// Use Array to store string s info: Char & Frequency
// Sliding window begins
int[] window = new int[26];
for (int i = 0; i < p.length(); i++) {
window[s.charAt(i) - 'a']++;
}
// Compare and see whether the first set of comparsion is valid
// if (isEqual(window, target)) {res.add(0);}
// Compare the rest of string s, sliding window begin to slide
int i = 0;
while (i <= s.length() - p.length()) {
if (isEqual(window, target)) {res.add(i);}
window[s.charAt(i) - 'a']--;
if (i + p.length() < s.length()) {
window[s.charAt(i + p.length()) - 'a']++;
}
i++;
}
return res;
}
private boolean isEqual(int[] arr, int[] target) {
for (int i = 0; i < target.length; i++) {
if (arr[i] != target[i]) {
return false;
}
}
return true;
}
}
Sliding Window
class Solution {
public List<Integer> findAnagrams(String s, String p) {
HashMap<Character, Integer> need = new HashMap<>();
for(char ch: p.toCharArray())
need.put(ch, need.getOrDefault(ch, 0) + 1);
int left = 0;
int right = 0;
int valid = 0;
int needed = p.length();
int n = s.length();
ArrayList<Integer> res = new ArrayList<>();
while(right < n){
char curr_ch = s.charAt(right);
if(need.containsKey(curr_ch)){
need.put(curr_ch, need.get(curr_ch) - 1);
if(need.get(curr_ch) >= 0)
valid++;
}
while(valid == needed){
if(right - left + 1 == needed)
res.add(left);
char char_removed = s.charAt(left);
if(need.containsKey(char_removed)){
need.put(char_removed, need.get(char_removed) + 1);
if(need.get(char_removed) > 0)
valid--;
}
left++;
}
right++;
}
return res;
}
}
Complexity:
class Solution {
public List<Integer> findAnagrams(String s, String p) {
HashMap<Character, Integer> need = new HashMap<>();
for(char ch: p.toCharArray())
need.put(ch, need.getOrDefault(ch, 0) + 1);
int left = 0;
int right = 0;
int valid = 0;
int needed = p.length();
int n = s.length();
ArrayList<Integer> res = new ArrayList<>();
while(right < n){
char curr_ch = s.charAt(right);
if(need.containsKey(curr_ch)){
need.put(curr_ch, need.get(curr_ch) - 1);
if(need.get(curr_ch) >= 0)
valid++;
}
while(valid == needed){
if(right - left + 1 == needed)
res.add(left);
char char_removed = s.charAt(left);
if(need.containsKey(char_removed)){
need.put(char_removed, need.get(char_removed) + 1);
if(need.get(char_removed) > 0)
valid--;
}
left++;
}
right++;
}
return res;
}
}
Time: O(n)
Space: O(n)
class Solution {
public List<Integer> findAnagrams(String s, String p) {
int sLen = s.length(), pLen = p.length();
if (sLen < pLen) {
return new ArrayList<Integer>();
}
List<Integer> ans = new ArrayList<Integer>();
int[] sCount = new int[26];
int[] pCount = new int[26];
for (int i = 0; i < pLen; ++i) {
++sCount[s.charAt(i) - 'a'];
++pCount[p.charAt(i) - 'a'];
}
if (Arrays.equals(sCount, pCount)) {
ans.add(0);
}
for (int i = 0; i < sLen - pLen; ++i) {
--sCount[s.charAt(i) - 'a'];
++sCount[s.charAt(i + pLen) - 'a'];
if (Arrays.equals(sCount, pCount)) {
ans.add(i + 1);
}
}
return ans;
}
}
public List
List<Integer> res = new LinkedList<>();
if (s == null || p == null || s.length() < p.length())
return res;
int[] ch = new int[26];
//统计p串字符个数
for (char c : p.toCharArray())
ch[c - 'a']++;
//把窗口扩成p串的长度
int start = 0, end = 0, rest = p.length();
for (; end < p.length(); end++) {
char temp = s.charAt(end);
ch[temp - 'a']--;
if (ch[temp - 'a'] >= 0)
rest--;
}
if (rest == 0)
res.add(0);
//开始一步一步向右移动窗口。
while (end < s.length()) {
//左边的拿出来一个并更新状态
char temp = s.charAt(start);
if (ch[temp - 'a'] >= 0)
rest++;
ch[temp - 'a']++;
start++;
//右边的拿进来一个并更新状态
temp = s.charAt(end);
ch[temp - 'a']--;
if (ch[temp - 'a'] >= 0)
rest--;
end++;
// 状态合法就存到结果集合
if (rest == 0)
res.add(start);
}
return res;
}
public List
List<Integer> res = new LinkedList<>();
if (s == null || p == null || s.length() < p.length())
return res;
int[] ch = new int[26];
for (char c : p.toCharArray())
ch[c - 'a']++;
int start = 0, end = 0, rest = p.length();
for (; end < p.length(); end++) {
char temp = s.charAt(end);
ch[temp - 'a']--;
if (ch[temp - 'a'] >= 0)
rest--;
}
if (rest == 0)
res.add(0);
while (end < s.length()) {
char temp = s.charAt(start);
if (ch[temp - 'a'] >= 0)
rest++;
ch[temp - 'a']++;
start++;
temp = s.charAt(end);
ch[temp - 'a']--;
if (ch[temp - 'a'] >= 0)
rest--;
end++;
if (rest == 0)
res.add(start);
}
return res;
}
class Solution {
public:
vector
int left = 0, right = 0;
int valid = 0;
vector<int> res; // 记录结果
while (right < s.size()) {
char c = s[right];
right++;
if (need.count(c)) {
window[c]++;
if (window[c] == need[c])
valid++;
}
while (right - left >= t.size()) {
if (valid == need.size())
res.push_back(left);
char d = s[left];
left++;
if (need.count(d)) {
if (window[d] == need[d])
valid--;
window[d]--;
}
}
}
return res;
}
};
- 思路描述:总觉得滑动窗口算法不如二分法直观。
#代码
class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
target = collections.Counter(p)
ans = []
for i in range(len(s)):
if i >= len(p):
target[s[i - len(p)]] += 1
if target[s[i - len(p)]] == 0:
del target[s[i - len(p)]]
target[s[i]] -= 1
if target[s[i]] == 0:
del target[s[i]]
if len(target) == 0:
ans.append(i - len(p) + 1)
return ans
- 时间复杂度: O(N)
- 空间复杂度: O(1)
class Solution: def findAnagrams(self, s: str, p: str) -> List[int]: target = collections.Counter(p) ans = [] for i in range(len(s)): if i >= len(p): target[s[i - len(p)]] += 1 if target[s[i - len(p)]] == 0: del target[s[i - len(p)]] target[s[i]] -= 1 if target[s[i]] == 0: del target[s[i]] if len(target) == 0: ans.append(i - len(p) + 1) return ans
class Solution(object):
def findAnagrams(self, s, p):
"""
:type s: str
:type p: str
:rtype: List[int]
"""
res = []
count = dict()
for c in p:
count[c] = 0
count2 = collections.Counter(p)
for right in range(len(s)):
left = right - len(p)
if left >= 0:
if s[left] in p:
count[s[left]] -= 1
if s[right] in p:
count[s[right]] += 1
if count == count2:
res.append(left + 1)
right += 1
return res
class Solution {
public:
std::vector<int> findAnagrams(std::string & s, std::string & p) {
if (s.size() < p.size()) {
return {};
}
std::unordered_map<char, int> dict1;
for (char & c : p) {
dict1[c]++;
}
std::vector<int> v1;
int n = s.size() - p.size() + 1;
std::unordered_map<char, int> temp_dict;
for (int j = 0; j < p.size(); ++j) {
temp_dict[s[j]] ++;
}
compare_map(temp_dict, dict1, v1, 0);
for (int i = 1; i < n; ++i) {
temp_dict[s[i - 1]] --;
temp_dict[s[i + p.size() - 1]] ++;
if(temp_dict[s[i - 1]] == 0) {
temp_dict.erase(s[i - 1]);
}
compare_map(temp_dict, dict1, v1, i);
}
return std::move(v1);
}
void compare_map(
std::unordered_map<char, int> & temp_dict,
std::unordered_map<char, int> & dict1,
std::vector<int> & v1,
int index
) {
bool temp_res = false;
if (temp_dict.size() == dict1.size()) {
temp_res = true;
for (const auto & item: dict1) {
if (temp_dict[item.first] != item.second) {
temp_res = false;
}
}
}
if (temp_res) {
v1.emplace_back(index);
}
}
};
/**
class Solution {
public List<Integer> findAnagrams(String s, String p) {
List<Integer> ret = new ArrayList<>();
int[] freq = new int[26];
for (int i = 0; i < p.length(); i++) {
freq[p.charAt(i) - 'a']++;
}
int left = 0, right = 0;
while (right < s.length()) {
while (right < s.length() && right < left + p.length()) {
freq[s.charAt(right) - 'a']--;
right++;
}
if (check(freq)) {
ret.add(left);
}
freq[s.charAt(left) - 'a']++;
left++;
}
return ret;
}
private boolean check(int[] freq) {
for (int i = 0; i < freq.length; i++) {
if (freq[i] != 0) {
return false;
}
}
return true;
}
}
Time: O(p + s)
Space: O(26) = O(1)
套用滑动窗口模版
var findAnagrams = function(s, p) {
let res = []
let need = new Map(), window = new Map();
for (let c of p){
need.set(c, (need.get(c) || 0)+1);
}
let left = 0, right = 0, valid = 0;
while(right < s.length){
const c = s[right];
right ++;
if(need.has(c)){
window.set(c, (window.get(c) || 0 )+1);
if(window.get(c) === need.get(c)){
valid ++;
}
}
while( right - left >= p.length){
const d = s[left];
if(valid === need.size){
res.push(left)
}
left ++;
if(need.has(d)){
if(window.get(d) === need.get(d)){
valid --;
}
window.set(d, window.get(d)-1)
}
}
}
return res
};
时间: O(n);
空间: O(1);
class Solution {
public List<Integer> findAnagrams(String s, String p) {
int m = s.length();
int n = p.length();
List<Integer> res = new ArrayList<>();
if (m < n) return res;
int[] dic = new int[26];
for (char c : p.toCharArray()) {
dic[c - 'a']++;
}
int count = 0;
for (int i = 0; i < 26; i++) {
if (dic[i] != 0) count++;
}
int left = 0, right = 0;
int b = 0;
while (right < m) {
dic[s.charAt(right) - 'a']--;
if (dic[s.charAt(right) - 'a'] == 0) {
b++;
}
if (right - left + 1 > n) {
dic[s.charAt(left) - 'a']++;
if (dic[s.charAt(left) - 'a'] == 1) {
b--;
}
left++;
}
if (b == count) res.add(left);
right++;
}
return res;
}
}
复杂度
class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
from collections import Counter
res = []
l = 0
c0 = Counter(p)
for r in range(len(s)):
if s[r] in c0:
c0[s[r]] -= 1
# print(f"{c0} {l} {r}")
if r >= len(p)-1:
if self.check(c0.values()):
res.append(l)
if s[l] in c0:
c0[s[l]] += 1
l += 1
return res
def check(self,t):
for i in t:
if i != 0:
return False
return True
from collections import Counter
class Solution: def findAnagrams(self, s: str, p: str) -> List[int]:
p_mapper = Counter(p)
p_size = len(p)
l = 0
r = 0
window = {}
result = []
while r < len(s):
cur_ch = s[r]
r += 1
if cur_ch not in p_mapper:
l = r
window = {}
else:
if cur_ch in window:
window[cur_ch] += 1
else:
window[cur_ch] = 1
if r-l == p_size:
if window == p_mapper:
result.append(l)
window[s[l]] -= 1
l += 1
else:
window[s[l]] -= 1
l += 1
return result
class Solution {
public List<Integer> findAnagrams(String s, String p) {
List<Integer> res = new LinkedList<>();
int[] sCount = new int[26];
int[] pCount = new int[26];
if (s.length() < p.length()) {
return res;
}
for(int i=0;i<p.length();i++){
sCount[s.charAt(i)-'a']++;
pCount[p.charAt(i)-'a']++;
}
if (Arrays.equals(sCount, pCount)) {
res.add(0);
}
for (int i = 0; i < s.length() - p.length(); i++) {
sCount[s.charAt(i) - 'a']--;
sCount[s.charAt(i + p.length()) - 'a']++;
if (Arrays.equals(sCount, pCount)) {
res.add(i + 1);
}
}
return res;
}
}
Time: O(n) Space: O(1)
滑动窗口 用2个数组(new Array(26))记录每个字符出现的次数
var findAnagrams = function(s, p) {
const sLen = s.length, pLen = p.length;
if (sLen < pLen) {
return [];
}
const ans = [];
const sCount = new Array(26).fill(0);
const pCount = new Array(26).fill(0);
for (let i = 0; i < pLen; ++i) {
++sCount[s[i].charCodeAt() - 'a'.charCodeAt()];
++pCount[p[i].charCodeAt() - 'a'.charCodeAt()];
}
if (sCount.toString() === pCount.toString()) {
ans.push(0);
}
for (let i = 0; i < sLen - pLen; ++i) {
--sCount[s[i].charCodeAt() - 'a'.charCodeAt()];
++sCount[s[i + pLen].charCodeAt() - 'a'.charCodeAt()];
if (sCount.toString() === pCount.toString()) {
ans.push(i + 1);
}
}
return ans;
};
class Solution: def findAnagrams(self, s: str, p: str) -> List[int]: ans = [] l, r = 0, 0 pCounter = Counter(p) sCounter = Counter() while r < len(s): c = s[r] if c in pCounter: sCounter[c] += 1
while l < r and sCounter[c] > pCounter[c]:
sCounter[s[l]] -= 1
l += 1
if sCounter == pCounter:
ans.append(l)
r += 1
else:
sCounter.clear()
r += 1
l = r
return ans
class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
s_len, p_len = len(s), len(p)
if s_len < p_len:
return []
ans = []
s_count = [0] * 26
p_count = [0] * 26
for i in range(p_len):
s_count[ord(s[i]) - 97] += 1
p_count[ord(p[i]) - 97] += 1
if s_count == p_count:
ans.append(0)
for i in range(s_len - p_len):
s_count[ord(s[i]) - 97] -= 1
s_count[ord(s[i + p_len]) - 97] += 1
if s_count == p_count:
ans.append(i + 1)
return ans
func findAnagrams(s string, p string) []int {
have, want := [26]int{}, [26]int{}; for i := range p { want[s[i]-'a']++ }
res := []int{}
left := 0
for right := range s {
have[s[right]-'a']++
if right >= len(p) { have[s[left]-'a']--; left++ }
if want == have { res = append(res, left) }
}
return res
}
Time: O(n), space O(n)
滑动窗口比较窗口中字符的出现次数。
class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
if len(s) < len(p): return []
count_p = collections.Counter(p)
count_s = defaultdict(int)
for i in range(len(p)):
count_s[s[i]] += 1
def same():
for char, val_p in count_p.items():
if count_s[char] != val_p:
return False
return True
l, r = 0, len(p) - 1
ans = []
while r < len(s):
if same():
ans.append(l)
if r == len(s) - 1: break
r += 1
count_s[s[r]] += 1
count_s[s[l]] -= 1
l += 1
return ans
//
// findAnagrams
// @Description:
// @param s
// @param p
// @return []int
//
func findAnagrams(s string, p string) []int {
ns := len(s)
mp := len(p)
left := 0
right := 0
hashP := make(map[byte]int)
window := make(map[byte]int)
ans := make([]int, 0)
for _, ch := range p {
hashP[byte(ch)]++
}
valid := 0
for right < ns {
ch := s[right]
right++
if _, ok := hashP[byte(ch)]; ok {
window[byte(ch)]++
if window[byte(ch)] == hashP[byte(ch)] {
valid++
}
}
for right-left >= mp {
if valid == len(hashP) {
ans = append(ans, left)
}
elemLeft := s[left]
left++
if _, ok:=hashP[byte(elemLeft)];ok {
if window[byte(elemLeft] == hashP[byte(elemLeft)]{
valid--
}
window[byte(elemLeft]--
}
}
}
return ans
}
//
// findAnagrams
// @Description:
// @param s
// @param p
// @return []int
//
func findAnagrams1(s string, p string) []int {
ns := len(s)
mp := len(p)
ans := make([]int,0)
if mp > ns {
return ans
}
var hashS [26]int
var hashP [26]int
for i,ch := range p {
hashS[s[i]-'a'] ++
hashP[ch - 'a'] ++
}
if hashS== hashP {
ans = append(ans, 0)
}
for i, ch := range s[:ns-mp] {
hashS[ch-'a']--
hashS[s[i+mp]-'a']++
if hashS == hashP {
ans = append(ans,i+1)
}
}
return ans
}
func findAnagrams2(s string, p string) []int {
ns := len(s)
mp := len(p)
ans := make([]int,0)
if mp > ns {
return ans
}
var hashS [26]int
var hashP [26]int
for _,ch := range p {
hashP[ch - 'a'] ++
}
left := 0
right := 0
for right < ns {
ch := s[right]
hashS[ch-'a']++
if (right - left +1) == mp{
if hashS == hashP {
ans = append(ans,left)
}
left ++
hashS[s[left-1]-'a']--
}
right++
}
return ans
}
/***
Solution
1. construct target_map: array[26] O(p)
2. current_map: array[26]
3. L = R = 0
4. iterate through the string O(n)
++current[c]
(1) target[c] = 0, L = R + 1, --cur[c] // does not appear
(2) current[c] > target[c], ++L until current[c] <= target[c] // too much
5. if R-L == p.size(), result++
Time: O(p) + O(n)
Space: O(p)
***/
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
unordered_map<char, int> target;
for (auto c : p) {
target[c] += 1;
}
unordered_map<char, int> cur;
vector<int> results;
int L = 0;
for (int R = 0; R < s.size(); ++R) {
// cout << "L" << L << " R " << R << endl;
char c = s[R];
++cur[c];
if (!target.count(c)) {
L = R + 1;
cur.clear();
continue;
}
while (cur[c] > target[c]) {
--cur[s[L]];
++L;
}
if ((R - L) == (p.size() - 1)) {
results.push_back(L);
}
}
return results;
}
};
/**
* leetcode: https://leetcode.cn/problems/find-all-anagrams-in-a-string/
* Tags: 滑动窗口
* @author liuyuan
* @date 2022-08-28 14:53
* @since 1.0.0
*/
interface KeyMap {
[key: string]: number
}
function findAnagrams(s: string, p: string): number[] {
// const sLen = s.length
// const pLen = p.length
// // 先判断长度比较
// if (sLen < pLen) {
// return []
// }
const need: KeyMap = {}
const win: KeyMap = {}
for (let i of p) {
need[i] = (need[i] || 0) + 1
}
let left = 0
let right = 0
// 与滑动窗口大小一样的字符串种类,如果出现次数跟 p 一样就 push
let val = 0
const result: number[] = []
// 右指针进行滑动
while (right < s.length) {
let c = s[right]
right++
if (need[c]) {
win[c] = (win[c] || 0) + 1
if (win[c] === need[c]) {
val++
}
}
// 这里需要判断不出窗口的情况,限制每次滑动窗口的大小都是等于 p.length
while (right - left >= p.length) {
if (val === Object.keys(need).length) {
result.push(left)
}
let d = s[left]
left++
if (need[d]) {
if (win[d] === need[d]) {
val--
}
win[d]--
}
}
}
return result
}
class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
ans = []
if len(p) > len(s):
return ans
p_counter = Counter(p)
n = len(p)
s_counter = Counter(s[:n])
if s_counter == p_counter:
ans.append(0)
l, r = 1, n
while r < len(s):
s_counter[s[l - 1]] -= 1
if s_counter[s[l - 1]] == 0:
del s_counter[s[l - 1]]
s_counter[s[r]] += 1
if s_counter == p_counter:
ans.append(l)
l += 1
r += 1
return ans
这里是滑动窗口的解决办法,但是这次比较简单,只需要处理滑动窗口,并对char数组进行排序,在对比一下targetchar即可,但是算法可能效率不高
public List<Integer> findAnagrams(String s, String p) {
List<Integer> ansList = new ArrayList<>();
int slideLen = p.length();
var chars = p.toCharArray();
Arrays.sort(chars);
for (int i = 0; i < s.length() - slideLen + 1; i++) {
if (findCharAtKey(chars, slideLen, s.substring(i, i + slideLen))) {
ansList.add(i);
}
}
return ansList;
}
private boolean findCharAtKey(char[] chars, int len, String targetString){
var targetChars = targetString.toCharArray();
Arrays.sort(targetChars);
return Arrays.equals(chars, targetChars);
}
滑动窗口
var findAnagrams = function(s, p) {
const sLen = s.length, pLen = p.length;
if (sLen < pLen) {
return [];
}
const ans = [];
const sCount = new Array(26).fill(0);
const pCount = new Array(26).fill(0);
for (let i = 0; i < pLen; ++i) {
++sCount[s[i].charCodeAt() - 'a'.charCodeAt()];
++pCount[p[i].charCodeAt() - 'a'.charCodeAt()];
}
if (sCount.toString() === pCount.toString()) {
ans.push(0);
}
for (let i = 0; i < sLen - pLen; ++i) {
--sCount[s[i].charCodeAt() - 'a'.charCodeAt()];
++sCount[s[i + pLen].charCodeAt() - 'a'.charCodeAt()];
if (sCount.toString() === pCount.toString()) {
ans.push(i + 1);
}
}
return ans;
};
滑动窗口
func findAnagrams(s string, p string) []int {
sLen,pLen := len(s),len(p)
var ans []int
if sLen<pLen {
return ans
}
var sCount,pCount [26]int
for i,v := range p{
sCount[s[i]-'a']++
pCount[v-'a']++
}
if sCount==pCount{
ans = append(ans,0)
}
for k,w := range s[:sLen-pLen]{
sCount[w-'a']--
sCount[s[k+pLen]-'a']++
if sCount==pCount{
ans = append(ans,k+1)
}
}
return ans
}
用一个定长的窗口扫一遍s,把s和p重合的词放进hash,窗口扫的hash和目标hash进行对比,一样则加到结果中
class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
if len(p) > len(s):
return []
target_hash_map = dict()
for w in p:
target_hash_map[w] = target_hash_map.get(w, 0) + 1
hash_map = dict()
l = 0
res = []
for r, w in enumerate(s):
if w in target_hash_map:
hash_map[w] = hash_map.get(w, 0) + 1
if r >= len(p):
if s[l] in target_hash_map:
hash_map[s[l]] = hash_map.get(s[l]) - 1
l += 1
if hash_map == target_hash_map:
res.append(l)
return res
import collections
class Solution:
def findAnagrams(self, s, p):
myDictP=collections.Counter(p)
myDictS=collections.Counter(s[:len(p)])
output=[]
i=0
j=len(p)
while j<=len(s):
if myDictS==myDictP:
output.append(i)
myDictS[s[i]]-=1
if myDictS[s[i]]<=0:
myDictS.pop(s[i])
if j<len(s):
myDictS[s[j]]+=1
j+=1
i+=1
return output
复杂度分析
class Solution {
public List<Integer> findAnagrams(String s, String p) {
int[] countP = new int[26];
char[] pArr = p.toCharArray();
for(char c:pArr){
countP[c-'a']++;
}
int[] countS = new int[26];
char[] sArr = s.toCharArray();
int left = 0;
int right = 0;
List<Integer> result = new ArrayList<>();
while(right<s.length()){
countS[sArr[right]-'a']++;
if(right-left+1>p.length()){
countS[sArr[left]-'a']--;
left++;
}
if(right-left+1==p.length() && isEqual(countP, countS)){
result.add(left);
}
right++;
}
return result;
}
public boolean isEqual(int[] p, int[] s){
for(int i =0;i<26;i++){
if(p[i]!=s[i]){
return false;
}
}
return true;
}
}
Complexity Analysis
var findAnagrams = function (s, p) {
const wordSet = new Set([...p]);
const wordMap = [...p].reduce((prev, cur) => {
return { ...prev, [cur]: (prev[cur] || 0) + 1 }
}, {});
const res = [];
const wordObj = {}, pLen = p.length;
let valid = 0;
for (let i = 0; i < s.length; i++) {
const right = s[i];
wordObj[right] = (wordObj[right] || 0) + 1;
if (wordObj[right] === wordMap[right]) {
valid++
}
if (i >= pLen) {
const left = s[i - pLen]
if (wordObj[left] === wordMap[left]) {
valid--
}
wordObj[left] = (wordObj[left] - 1) || 0;
}
if (valid === wordSet.size) {
res.push(i - pLen + 1)
}
}
return res;
}
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
int s_n =s.size();
int p_n = p.size();
vector<int> ans;
if(s_n<p_n)return ans;
unordered_map<int,int> map;
int p1 =0;
int p2 =0;
for(auto c:p){
map[c]++;
}
while (p2<p_n){
int c_p2 = s[p2++];
map[c_p2]--;
if(!map[c_p2])map.erase(c_p2);
}
if(map.empty())ans.push_back(p1);
while (p2<s_n){
int c_p2 = s[p2++];
map[c_p2]--;
if(!map[c_p2])map.erase(c_p2);
int c_p1 = s[p1++];
map[c_p1]++;
if(!map[c_p1])map.erase(c_p1);
if(map.empty())ans.push_back(p1);
}
return ans;
}
};
class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
s_len, p_len = len(s), len(p)
if s_len < p_len:
return []
ans = []
s_count = [0] * 26
p_count = [0] * 26
for i in range(p_len):
s_count[ord(s[i]) - 97] += 1
p_count[ord(p[i]) - 97] += 1
if s_count == p_count:
ans.append(0)
for i in range(s_len - p_len):
s_count[ord(s[i]) - 97] -= 1
s_count[ord(s[i + p_len]) - 97] += 1
if s_count == p_count:
ans.append(i + 1)
return ans
class Solution {
public List<Integer> findAnagrams(String s, String p) {
int[] cnt = new int[128];
for (char c : p.toCharArray()) cnt[c]++;
int lo = 0, hi = 0;
List<Integer> res = new ArrayList<>();
while (hi < s.length()) {
if (cnt[s.charAt(hi)] > 0) {
cnt[s.charAt(hi++)]--;
if (hi - lo == p.length()) res.add(lo);
} else {
cnt[s.charAt(lo++)]++;
}
}
return res;
}
}
滑动窗口+计数
class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
if len(p) > len(s):
return []
s_cnt, p_cnt = [0]*26, [0]*26
res = []
# index=0
for i in range(len(p)):
p_cnt[ord(p[i]) - ord('a')] += 1
s_cnt[ord(s[i]) - ord('a')] += 1
if p_cnt == s_cnt: res.append(0)
for i in range(len(p), len(s)): #position in s
s_cnt[ord(s[i]) - ord('a')] += 1
s_cnt[ord(s[i - len(p)]) - ord('a')] -= 1
if s_cnt == p_cnt:
res.append(i - len(p) + 1)
return res
双指针 + 哈希表
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
unordered_map<char, int> hp;
unordered_map<char, int> hs;
int n = p.size();
vector<int> res;
for (char c : p) hp[c] ++;
for (int i = 0, j = 0; i < s.size(); i ++) {
hs[s[i]] ++;
while (hs[s[i]] > hp[s[i]]) hs[s[j ++]] --;
if (n == i - j + 1) res.push_back(j);
}
return res;
}
};
from typing import List
from collections import Counter
class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
l, r = 0, len(p)
p_hash = Counter(p)
cur_hash = Counter(s[l:r])
ans = []
while r<=len(s):
if cur_hash == p_hash:
ans.append(l)
cur_hash[s[l]] -= 1
if cur_hash[s[l]] <= 0:
cur_hash.pop(s[l])
if r<len(s):
cur_hash[s[r]] += 1
l +=1
r +=1
return ans
滑动窗口,用数组存字符的个数,匹配是否跟 p 的数组相等
vector<int> findAnagrams(string s, string p) {
int n1 = s.size(), n2 = p.size();
if (n1 < n2) return {};
vector<int> ump(26);
vector<int> now(26);
for (char c : p) {
ump[c - 'a']++;
}
vector<int> res;
for (int i = 0; i < n2; ++i) {
now[s[i] - 'a']++;
}
if (now == ump) res.push_back(0);
for (int i = 0; i < n1 - n2; ++i) {
now[s[i] - 'a']--;
now[s[i+n2] - 'a']++;
if (now == ump) res.push_back(i + 1);
}
return res;
}
- 时间复杂度: O(NΣ), N 是 nums 的长度
- 空间复杂度: O(Σ),Σ 是字母表长度
// O(n), O(1)
class Solution {
public List<Integer> findAnagrams(String s, String p) {
int[] cnt = new int[128];
for (int i = 0; i < p.length(); i++)
cnt[p.charAt(i)]++; // 所需字母数量, 其他都是0
int need = p.length();
List<Integer> res = new LinkedList<>();
for (int l = 0, r = 0; r < s.length(); r++) {
char c = s.charAt(r);
cnt[c]--;
// 当字母数量多了 / 包含不合法的字母
while (l <= r && cnt[c] < 0)
cnt[s.charAt(l++)]++;
if (r - l+ 1 == p.length()) res.add(l);
}
return res;
}
}
class Solution {
public List<Integer> findAnagrams(String s, String p) {
// 使用固定窗口, 小写字母组成,我们就可以使用两个数组
int len1 = s.length();
int len2 = p.length();
if(len1 < len2) return new ArrayList<>();
// 开始滑动窗口
int left = 0, right = len2;
int[] a = new int[26];
int[] b = new int[26];
ArrayList<Integer> c = new ArrayList<>();
for(int i = 0; i < len2; i++){
a[s.charAt(i) - 'a']++;
b[p.charAt(i) - 'a']++;
}
if(Arrays.equals(a, b)) c.add(0);
while(right < len1){
a[s.charAt(right) - 'a']++;
a[s.charAt(left) - 'a']--;
if(Arrays.equals(a, b)) c.add(left + 1);
right++;
left++;
}
return c;
}
}
Thinking:
class Solution {
public List<Integer> findAnagrams(String s, String p) {
int sLen = s.length(), pLen = p.length();
if (sLen < pLen) {
return new ArrayList<Integer>();
}
List<Integer> ans = new ArrayList<Integer>();
int[] sCount = new int[26];
int[] pCount = new int[26];
for (int i = 0; i < pLen; ++i) {
++sCount[s.charAt(i) - 'a'];
++pCount[p.charAt(i) - 'a'];
}
if (Arrays.equals(sCount, pCount)) {
ans.add(0);
}
for (int i = 0; i < sLen - pLen; ++i) {
--sCount[s.charAt(i) - 'a'];
++sCount[s.charAt(i + pLen) - 'a'];
if (Arrays.equals(sCount, pCount)) {
ans.add(i + 1);
}
}
return ans;
}
}
Time Complexity O(m+(n−m)×Σ) Space Complexity O(Σ)
滑动窗口,每次只需要关心进出窗口的字符。
from collections import Counter
from typing import List
class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
s_len, p_len = len(s), len(p)
if s_len < p_len:
return []
char_diff_counter = Counter(p)
win_counter = Counter(s[:p_len])
diff_char_count = 0
for ch in char_diff_counter:
char_diff_counter[ch] -= win_counter[ch]
diff_char_count += (char_diff_counter[ch] != 0)
result = []
for i in range(s_len - p_len + 1):
if diff_char_count == 0:
result.append(i)
if s[i] in char_diff_counter:
char_diff_counter[s[i]] += 1
if char_diff_counter[s[i]] == 0:
diff_char_count -= 1
elif char_diff_counter[s[i]] == 1:
diff_char_count += 1
if i + p_len < s_len and s[i + p_len] in char_diff_counter:
char_diff_counter[s[i + p_len]] -= 1
if char_diff_counter[s[i + p_len]] == 0:
diff_char_count -= 1
elif char_diff_counter[s[i + p_len]] == -1:
diff_char_count += 1
return result
438. 找到字符串中所有字母异位词
入选理由
暂无
题目地址
https://leetcode-cn.com/problems/find-all-anagrams-in-a-string/
前置知识
题目描述
字符串只包含小写英文字母,并且字符串 s 和 p 的长度都不超过 20100。
说明:
字母异位词指字母相同,但排列不同的字符串。 不考虑答案输出的顺序。 示例 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" 的字母异位词。