【多次过】【滑动窗口】Lintcode 647. Find All Anagrams in a String

给定一个字符串 s 和一个 非空字符串 p ,找到在 s 中所有关于 p 的字谜的起始索引。
字符串仅由小写英文字母组成,字符串 s 和 p 的长度不得大于 40,000。
输出顺序无关紧要。

样例

给出字符串 s = "cbaebabacd" p = "abc"
返回 [0, 6]

子串起始索引 index = 0 是 "cba",是"abc"的字谜.
子串起始索引 index = 6 是 "bac",是"abc"的字谜.

解题思路:

哈希方式

分析题目,要找的是待查询序列的一个子序列,这个子序列可以是给定目标序列的任意顺序。我们首先要考虑如何满足所谓的任意顺序。这里很容易想到采取一种哈希策略,使包含目标序列的字符拥有相同的哈希值,从而任何顺序的字符序列都可以被快速识别出来。这样的想法是完全正确的,相比去产生所有可能的序列,这种方法无疑拥有更低的时间复杂度。这种方法还是比较好想到,只需要一个字符数组,保存目标序列各个字符出现的次数即可。这样,只要满足对应数组结构的子序列,就是一个符合要求的子序列。

滑动窗口(sliding window)

    字符串匹配问题一个常见的解法就是滑动窗口了,我们利用上述得到的哈希数组,来移动滑动窗口,若窗口内的字符串满足该数组,我们就记录窗口左部的下标作为返回值之一。方法类似于Lintcode 384. 最长无重复字符的子串

class Solution {
public:
    /**
     * @param s: a string
     * @param p: a string
     * @return: a list of index
     */
    vector<int> findAnagrams(string &s, string &p) 
    {
        // write your code here
        int i=0 , j=-1;//[i,j]为滑动窗口
        
        int freq[128] = {0};//记录p中每个字符出现的频次
        for(char c : p)
            freq[c]++;
        
        vector<int> res;
        while(i < s.size())
        {
            if(j+1 < s.size() && freq[s[j+1]] > 0)
                freq[s[++j]]--;
            else
                freq[s[i++]]++;

            if(j-i+1 == p.size())
                res.push_back(i);
        }
        
        return res;
    }
};




猜你喜欢

转载自blog.csdn.net/majichen95/article/details/80840483