438. Find All Anagrams in a String

xiaoxiao2021-02-28  34

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".做这道题目的时候正在生病中,想想每天刷一道leetcode的习惯不能破,还是坚持做下来了,为自己点个赞。

当然做的是一塌糊涂,做了一个小时多,用了一个很扯淡的方法AC了,先来说说我的做法。

这个题目明显是Hash表应用,但我的想法局限在只是用一个hash表里面了(建立string p的Hash表,在划窗遍历s时减去Hash表中相应项的数值,若在一个窗口中Hashp数组为全0,则是Anagrams,若某个字母进入窗口后使得Hashp中对应的项小于0,则窗口需要向后滑动),这样在划窗遍历string s的时候非常麻烦,需要定义了head和tail两个指针表示窗的起始和终止坐标,flag表示的是当窗口新进入一个字母使得Hash表中某一项小于0(即已经不可能是Anagrams时)的情况。具体的head的前进规则:如果flag为0,且当前窗口满足条件,则前进一格,否则一直前进到Hashp[++head]  == 0为止;如果当前的flag为1,则head前进到s[head] == s[tail - 1]的位置。

这么说太模糊不清了,以Example1为例具体说明一下:

s: "cbaebabacd" p: "abc"0. Hashp的值为[1,1,1,0......,0],开始时head和tail均在起始位置为0。

1. 当第一次窗口填满时,Hashp的值为全0,此时head = 0, tail= 2,记录下起始点head值。

2. 窗口向后移动一格,head = 1,tail走到3,发现值为e使得Hashp[4](即e-'a')为-1,此时说明这个窗口不满足条件,head前进至第一个等于e的位置且要越过它,这里前进到head = 4,此时tail = 4.

3. tail继续往后走至tail=6,窗口中为"bab",不满足条件,同2,head越过第一个和tail-1所在位置相同的值即b,到达head = 5.

4. head = 5后tail走到7,窗口中为"aba",不满足条件,同2,head越过a达到b,head = 6。

5. head = 6后tail走到8,窗口中为"bac",满足条件,记录此时起始点head的值,然后窗口往后移一格,head = 7。

6. 新入的值d使得Hashp[3]为-1,head一直走到head = 9才使得Hashp[3]非负,此时head值超过了s.size() - p.size(),循环结束。

class Solution { public: vector<int> findAnagrams(string s, string p) { vector<int> res; if (s.size() < p.size()) return res; vector<int> Hashp(26, 0); for (int i = 0; i < p.size(); i++) Hashp[p[i] - 'a']++; int head = 0; int tail = 0; int ComeinNum = p.size() - head; int flag = 0; while (head <= s.size() - p.size()) { if (tail < head) tail = head;   while (tail < s.size() && tail < head + p.size()) { Hashp[s[tail] - 'a']--; if (Hashp[s[tail] - 'a'] < 0) { tail++; flag = 1; break; } tail++; } if (flag == 1) { while (s[head] != s[tail - 1]) { Hashp[s[head] - 'a']++; head++; } Hashp[s[head] - 'a']++; head++; } else { int sum = 0; for (int i = 0; i < 26; i++) sum += Hashp[i]; if (sum == 0) { res.push_back(head); Hashp[s[head] - 'a']++; head++; } else { while (Hashp[++head] < 0) Hashp[s[head - 1] - 'a']++; } } flag = 0; } return res; } };

后来一看别人做的方法,无语了,为何自己这么傻(⊙_⊙)?

既然我维护Hashp数组这么麻烦,那干脆不用维护了,直接再开一个数组Hashs表示滑动窗口里的情况就好了啊。

窗口每次都是一进一出,更新完Hashs后与Hashp对比,注意这里index的值表示的是窗口的结尾值。

class Solution {public:    vector<int> findAnagrams(string s, string p) {        vector<int> res;        if(s.size() < p.size())            return res;        vector<int> Hashs(26,0);        vector<int> Hashp(26,0);        for(int index = 0;index < p.size();index++)        {            Hashs[s[index]-'a']++;            Hashp[p[index]-'a']++;        }        if(Hashs == Hashp)           res.push_back(0);        for(int index = p.size();index < s.size();index++)        {            Hashs[s[index] -'a']++;            Hashs[s[index - p.size()] - 'a']--;            if(Hashs == Hashp)               res.push_back(index - p.size() + 1);        }        return res;    }};

转载请注明原文地址: https://www.6miu.com/read-2630654.html

最新回复(0)