每日一題:統計重複個數

由 n 個連接的字符串 s 組成字符串 S,記作 S = [s,n]。例如,[“abc”,3]=“abcabcabc”。

如果我們可以從 s2 中刪除某些字符使其變爲 s1,則稱字符串 s1 可以從字符串 s2 獲得。例如,根據定義,“abc” 可以從 “abdbec” 獲得,但不能從 “acbbe” 獲得。

現在給你兩個非空字符串 s1 和 s2(每個最多 100 個字符長)和兩個整數 0 ≤ n1 ≤ 106 和 1 ≤ n2 ≤ 106。現在考慮字符串 S1 和 S2,其中 S1=[s1,n1] 、S2=[s2,n2] 。

請你找出一個可以滿足使[S2,M] 從 S1 獲得的最大整數 M 。

示例:
輸入:
s1 =“acb”,n1 = 4
s2 =“ab”,n2 = 2

返回:
2

/*
方法一:找出循環節
*/
class Solution {
public:
    int getMaxRepetitions(string s1, int n1, string s2, int n2) {
        if (n1 == 0) {
            return 0;
        }

        int s1cnt = 0, index = 0, s2cnt = 0;
        /*
        recall是我們用來找循環節的變量,它是一個哈希映射
        我們如何找循環節?假設我們遍歷了s1cnt個s1,此時匹配到了第s2cnt個s2中的第index個字符
        如果我們之前遍歷了s1cnt'個s1時,匹配到的是第s2cnt'個s2中同樣的第index個字符,那麼就有循環節了
        我們用(s1cnt',s2cnt',index)和(s1cnt,s2cnt,index)表示兩次包含相同index的匹配結果
        那麼哈希映射中的鍵就是index,值就是(s1cnt',s2cnt')這個二元組
        循環節就是:
        -前s1cnt'個s1包含了s2cnt'個s2;
        -以後的每(s1cnt - s1cnt')個s1包含了(s2cnt-s2cnt')個s2
        那麼還會剩下(n1 - s1cnt)% (s1cnt - s1cnt')個s1,我們對這些與s2進行暴力匹配
        注意s2要從第index個字符開始匹配
        */
       unordered_map<int, pair<int, int>> recall;
       pair<int, int> preLoop, inLoop;
       while (true) {
           // 我們遍歷一個s1,看看能不能找不到循環節
           ++s1cnt;
           for (char ch: s1) {
               if (ch == s2[index]) {
                   index += 1;
                   if (index == s2.size()) {
                       ++s2cnt;
                       index = 0;
                   }
               }
           }
           // 沒有找到循環節,所有的s1就用完了
           if (s1cnt == n1) {
               return s2cnt / n2;
           }
           // 出現了之前的index,表示找到了循環節
           if (recall.count(index)) {
               auto [s1cntPrime, s2cntPrime] = recall[index];
               // 前s1cnt'個s1包含了s2cnt'個s2
               preLoop = {s1cntPrime, s2cntPrime};
               // 以後的每(s1cnt - s2cnt')個s1包含了(s2cnt - s2cnt')個s2
               inLoop = {s1cnt - s1cntPrime, s2cnt - s2cntPrime};
               break;
           }
           else {
               recall[index] = {s1cnt, s2cnt};
           }
        }
        // ans存儲的S1包含的s2數量,考慮到之前的preLoop和inLoop
        int ans = preLoop.second + (n1 - preLoop.first) / inLoop.first * inLoop.second;
        // S1的末尾還剩下一些s1(數量不足以構成循環節),我們暴力進行匹配
        int rest = (n1 - preLoop.first) % inLoop.first;
        for (int i = 0; i < rest; i++) {
            for (char ch : s1) {
                if (ch == s2[index]) {
                    index++;
                    if (index == s2.size()) {
                        ans++;
                        index = 0;
                    }
                }
            }
        }
        // S1包含ans個s2,那麼久包含ans / n2個S2;
        return ans / n2;
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章