[LeetCode] Find All Anagrams in a String

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,在s中找出p的所有变位词的头索引。

思路:用一维数组cnt存储p的所有字符及其出现次数(因为字符由ASCII码组成,所以申请一个大小为128的vector即可,用vector的索引值代表字符,vector的元素值代表字符出现次数),然后开始遍历s的每一位的同时遍历p,这时需要重新申请一个临时数组tmp来代替cnt,并对tmp的 值进行操作(访问过p的值后并让tmp的值减1)。最后将符合条件的头索引放入结果数组res中即可。

这是一个蛮力迭代算法,优点是思路清晰,缺点是所用的时间复杂度较高。O(s * p)

class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        if (s.empty())
            return {};
        vector<int> res, cnt(128, 0);
        int sn = s.size(), pn = p.size(), i = 0;
        for (char c : p)
            cnt[c]++;
        while (i < sn) {
            bool success = true;
            vector<int> tmp = cnt;
            for (int j = i; j < i + pn; j++) {
                if (tmp[s[j]]-- <= 0) {
                    success = false;
                    break;
                }
            }
            if (success)
                res.push_back(i);
            i++;
        }
        return res;
    }
};
// 543 ms

通过上面的思路,很容易想到这是一个滑动窗口模型。

首先建立一个哈希表m统计p中字符出现的次数。使用left和right表示滑动窗口的左右边界,cnt表示字符串p中需要匹配的字符个数。然后开始循环

如果右边界字符已经在m中,说明该字符在p中出现,令cnt减1,然后m中该字符出现的次数也减1,右边界加1。

如果此时cnt为0,则说明p中的字符都匹配成功,将左边界放入结果数组中。

如果此时right与left之差等于p的长度, 说明此时应该去掉最左边的字符,如果这个字符在m中出现次数大于等于0,说明该字符是p中的字符。所以令cnt加1。

class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        if (s.empty()) 
            return {};
        vector<int> res, m(128, 0);
        int left = 0, right = 0, cnt = p.size(), n = s.size();
        for (char c : p) 
            m[c]++;
        while (right < n) {
            if (m[s[right++]]-- >= 1) 
                cnt--;
            if (cnt == 0) 
                res.push_back(left);
            if (right - left == p.size() && m[s[left++]]++ >= 0) 
                cnt++;
        }
        return res;
    }
};
// 33 ms

 

posted @ 2017-10-12 11:35  immjc  阅读(164)  评论(0编辑  收藏  举报