统计重复个数

由 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 。

在我看来这道题的难点在于读懂题意,[S2,M]表示在将s2循环n2次的基础上,再将循环后得到的字符串再循环M次,求这个M的最大值,因此我们可以去寻找s1和s2的公共循环部分,起初我想的是s1循环多少次能够找到一个s2,但是这样得到的结果会比之前所说的方法得到的结果更少,原因是,在s1的末尾可能再次出现s2的开头部分,因此我们需要去寻找公共循环的部分。

int getMaxRepetitions(string s1, int n1, string s2, int n2) {
    if (n1 == 0) {
        return 0;
    }
    int s1cnt = 0, index = 0, s2cnt = 0;
    map<int, pair<int, int>> recall;
    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;
                }
            }
        }
        if (s1cnt == n1) {
            return s2cnt / n2;
        }
        if (recall.count(index)) {
            auto [s1cnt_prime, s2cnt_prime] = recall[index];
            pre_loop = {s1cnt_prime, s2cnt_prime};
            in_loop = {s1cnt - s1cnt_prime, s2cnt - s2cnt_prime};
            break;
        }
        else {
            recall[index] = {s1cnt, s2cnt};
        }
    }
    int ans = pre_loop.second + (n1 - pre_loop.first) / in_loop.first * in_loop.second;
    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()) {
                    ++ans;
                    index = 0;
                }
            }
        }
    }
    return ans / n2;
}
posted @ 2020-04-19 10:35  ~吹梦到西洲~  阅读(220)  评论(0编辑  收藏  举报