Find All Anagrams in a String

 

 1. 解析

題目大意,在字符串中查找給定的子序列,該子序列只要求出現的字符相同,而不要求順序一樣。

 2. 分析

整體上,這道題還是比較容易想到的。每次在s串中切割長度和p相同的字符串,然後比較它們出現的字符是否相同,如果一樣,記錄起點的位置;如果不一樣,說明兩個子串不相等。將字符串往後移動,逐個切割判斷即可。這裏的關鍵是如果判斷兩個子串出現的字符是一樣的,我剛開始想到的解法是,分別將這兩個子串進行排序,這樣就可以直接比較了,但這種方法是過不了OJ的,因爲當子串p特別大的時候,調用系統的sort算法是特別耗時的。最好的做法無非就是利用數組進行存儲,因爲字符串都是由26個小寫組成,所以我們只需建立一個26個長度的序列就可以表示它們出現的情況。用數組的下標表示出現的字符,即'a'就是0,'b'就是1,......,以此類推。

class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        int p_len = p.length();
        vector<int> res;
        if (s.length() < p_len) return res; //如果查找的子串的長度大於母串
        vector<int> s_count(26, 0);
        vector<int> p_count(26, 0);
        for (int i = 0; i < p_len; ++i){ //記錄待查找字符串p的字符出現次數以及在字符串s中前p字符串長度的字符出現個數
            ++s_count[s[i]-'a'];
            ++p_count[p[i]-'a'];
        }
        if (s_count == p_count) res.push_back(0);
        for (int i = p_len; i < s.length(); ++i){
            --s_count[s[i-p_len]-'a'];
            ++s_count[s[i]-'a'];
            if (s_count == p_count)
                res.push_back(i-p_len+1);
        }
        return res;
    }
};

 滑動窗口解法:

left-----窗口的左邊界,right-------窗口的右邊界,cnt-----要匹配的字符總數,m------存儲字符串p中字符出現的個數

當字符串s中的某段字串出現的字符和p中出現的一樣時,cnt就會變成0,將左邊界left記錄下來;當窗口的大小大於設定的大小時,要將左邊界右移,同時判斷左邊界出現的字符是否在p中,如果存在,去掉後,意味着要匹配的字符個數要增加1個(關鍵的地方)。

class Solution {
public:
    vector<int> findAnagrams(string s, string p){
        vector<int> res;
        vector<int> m(26, 0);
        for (char ch : p) ++m[ch-'a']; //記錄p串中每個字符出現的次數
        int left = 0, right = 0, len = s.length(), cnt = p.length();
        
        while (right < len) { //維持的整個窗口大小爲子串p的長度
            if (m[s[right++]-'a']-- >= 1) cnt--;
            if (cnt == 0) res.push_back(left); //若當前p出現的字符都被匹配,則意味着出現相同的子串
            if (right - left == p.length() && m[s[left++]-'a']++ >= 0) cnt++; //若當前窗口的大小比設定窗口大1,則左邊界往右移動
        }
        return res;
    }
};

[1]https://www.cnblogs.com/grandyang/p/6014408.html

發佈了155 篇原創文章 · 獲贊 2 · 訪問量 2361
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章