【LeetCode】466. 统计重复个数

106 阅读2分钟

题目链接

image.png

image.png

Python3

方法: 找循环节(m个s1对应n个s2) O(s1×s2)O(s2)\lgroup O(|s_1|\times|s_2|)、O(|s_2|)\rgroup

官方题解

image.png

class Solution:
    def getMaxRepetitions(self, s1: str, n1: int, s2: str, n2: int) -> int:
        # 构建 哈希表 s2字母的下标index:(s1cnt,s2cnt)
        # 找循环节, 查找规律  m 个 s1 凑成 n 个 s2 的循环
        index, s1cnt, s2cnt = 0, 0, 0
        recall = dict()
        while True:
            s1cnt += 1
            for ch in s1:
                if ch == s2[index]:
                    index += 1
                    if index == len(s2): # 匹配完一次 s2
                        s2cnt, index = s2cnt + 1, 0

            
            if s1cnt == n1:
                return s2cnt // n2 


            # 出现了之前的index, 表示找到了循环节
            if index in recall:
                s1cnt_prime, s2cnt_prime = recall[index]  # # 前 s1cnt' 个 s1 包含了 s2cnt' 个 s2
                pre_loop = (s1cnt_prime, s2cnt_prime)   # 起始位置的数量
                in_loop = (s1cnt - s1cnt_prime, s2cnt - s2cnt_prime) # 以后的每 (s1cnt - s1cnt') 个 s1 包含了 (s2cnt - s2cnt') 个 s2  
                break
            else:
                recall[index] = (s1cnt, s2cnt)

        # res 存储的是 S1 包含的 s2 的数量,考虑的之前的 pre_loop 和 in_loop
        res = pre_loop[1] + (n1 - pre_loop[0]) // in_loop[0] * in_loop[1]
        # S1 的末尾还剩下一些 s1,我们暴力进行匹配
        rest = (n1 - pre_loop[0]) % in_loop[0]
        for i in range(rest):
            for ch in s1:
                if ch == s2[index]:
                    index += 1
                    if index == len(s2):
                        res, index = res + 1, 0
        # S1 包含 res 个 s2,那么就包含 res / n2 个 S2
        return res // n2

image.png

C++

方法: 找循环节(m个s1对应n个s2) O(s1×s2)O(s2)\lgroup O(|s_1|\times|s_2|)、O(|s_2|)\rgroup

class Solution {
public:
    int getMaxRepetitions(string s1, int n1, string s2, int n2) {
        int s1cnt = 0, s2cnt = 0, index = 0;
        unordered_map<int, pair<int, int>> matched;
        pair<int, int>pre_loop, in_loop;
        while (true){
            ++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 (matched.count(index)){
                auto [s1cnt_prime, s2cnt_prime] = matched[index];
                pre_loop = {s1cnt_prime, s2cnt_prime};
                in_loop = {s1cnt - s1cnt_prime, s2cnt - s2cnt_prime};
                break;
            }else{
                matched[index] = {s1cnt, s2cnt};
            }
        }
        int res = pre_loop.second + (n1 - pre_loop.first) / in_loop.first * in_loop.second;

        // 匹配 末尾的 s1
        int rest = (n1 - pre_loop.first) % in_loop.first;
        for (int i = 0; i < rest; ++i){
            for (char ch : s1){
                if (ch == s2[index]){
                    ++index;
                    if (index == s2.size()){
                        ++res;
                        index = 0;
                    }
                }
            }
        }
        return res / n2;
    }
};