字符串转换

给你两个长度都为 n 的字符串 s 和 t 。你可以对字符串 s 执行以下操作:

将 s 长度为 l (0 < l < n)的 后缀字符串 删除,并将它添加在 s 的开头。
比方说,s = 'abcd' ,那么一次操作中,你可以删除后缀 'cd' ,并将它添加到 s 的开头,得到 s = 'cdab' 。
给你一个整数 k ,请你返回 恰好 k 次操作将 s 变为 t 的方案数。

1. 动态规划 + 矩阵快速幂 + KMP算法

由于结果很大,考虑动态规划的状态转移
状态的转移需要知道字符串循环节的个数,使用KMP求s的循环节个数,这里拆环为链
最后由于迭代次数过多,这里需要使用矩阵快速幂

class Solution {
public:
    const int MOD = 1e9 + 7;
    int numberOfWays(string s, string t, long long k) {
        int n = s.size();//长度决定可以移动的距离和操作数
        //dp1[i]表示i次操作后等于t的方案数,dp1[i] = dp1[i-1]*(c-1) + dp2[i-1]*c
        //dp2[i]表示i次操作后不等于t的方案数dp2[i] = dp1[i-1]*(n-c) + dp2[i-1]*(n-1-c)
        //下面我们要求s中有多少个循环节c,然后运算迭代k次
        int c = search(s+s.substr(0,n-1),t);//寻找对应字符串中t出现的次数
        if(c==0) return 0;//无法通过操作得到
        vector<vector<int>> matrix = {
            {c-1,c},
            {n-c,n-1-c}
        };
        matrix = fastpower(matrix,k);
        return matrix[0][s!=t];
    }
    int search(string text,string pattern){
        //KMP算法
        int n = pattern.size();
        vector<int> fail(n, -1);//记录的是上一个相同位置
        for (int i = 1; i < n; ++i) {
            int j = fail[i - 1];
            while (j != -1 && pattern[j + 1] != pattern[i]) 
                j = fail[j];
            if (pattern[j + 1] == pattern[i]) 
                fail[i] = j + 1;
        }
        //计算出现多少次
        
        int cnt = 0; int idx = -1;//模板串下标
        
        for(int i=0;i<text.size();i++){//遍历主串
            while(idx!=-1&&pattern[idx+1]!=text[i])
                idx = fail[idx]; //重置模板串下标
            if(pattern[idx+1]==text[i]) idx++;
            if(idx==pattern.size()-1){
                cnt++;
                idx = fail[idx];
            }
        }
        return cnt;
    }

    vector<vector<int>> mutiply(vector<vector<int>>& left,vector<vector<int>> &right){
        int m = left.size(); int n = right.size();
        vector<vector<int>> res(m,vector<int>(m));
        for(int i=0;i<m;i++)  //遍历left 的 m行
            for(int j=0;j<m;j++) //遍历right 的 m列
                for(int k=0;k<n;k++) //遍历相乘的每一个数
                    res[i][j] = (res[i][j] + ((long long)left[i][k]*right[k][j])%MOD)%MOD;
        return res;
    }
    vector<vector<int>> identify(int m){
        vector<vector<int>> res(m,vector<int>(m));
        for(int i=0;i<m;i++)
            res[i][i] = 1;
        return res;
    }

    vector<vector<int>> fastpower(vector<vector<int>> cur, long long n){
        int m = cur.size();
        vector<vector<int>> res = identify(m);//初始化单位矩阵
        while(n){//进行快速幂运算
            if(n&1) res = mutiply(res,cur);
            cur = mutiply(cur,cur);//倍增
            n>>=1;
        }
        return res;
    }
};
posted @ 2023-09-11 19:53  失控D大白兔  阅读(19)  评论(0编辑  收藏  举报