找到所有好字符串

给你两个长度为 n 的字符串 s1 和 s2 ,以及一个字符串 evil 。请你返回 好字符串 的数目。
好字符串 的定义为:它的长度为 n ,字典序大于等于 s1 ,字典序小于等于 s2 ,且不包含 evil 为子字符串

一. 数位dp + KMP算法

const int MOD = 1e9 + 7;

class Solution {
public:
    int findGoodStrings(int n, string s1, string s2, string evil) {
        //遍历下标,在s1[i]和s2[i]之间枚举字符
        //不受限的情况下,可以取26个字母
        //后面能否枚举,受前面的制约,想某种方法将前面的特征存下,用作dp数组的第二维,这里用前面已匹配的字符位数
        int len = evil.size(); int memo[n][len];
        memset(memo,-1,sizeof(memo));
        //获取next数组
        vector<int> fail(len, -1);//初始无前一元素,跳转-1,同时表示无相等元素,因为后面还要增
        for (int i = 1; i < len; i++){//从1开始,评估每个位置应跳转的地方
            int j = fail[i - 1];//前一元素的跳转位置
            while (j != -1 && evil[j + 1] != evil[i]) //跳转后的后一元素继续比较当前元素
                j = fail[j];//,匹配失效,继续跳转,压缩转移位置
            if (evil[i] == evil[j + 1])   fail[i] = j + 1;//相等记录该位置
            //否则跳转到-1
        }

        function<int(int, int ,bool, bool)> f = [&](int i,int j,bool downlimit,bool uplimit) -> int {//视情况记录已遍历值的某种特征,如1的个数,mask状态,
            if (j == len) return 0; //已枚举字符串包含evil,不合法,返回0
            if (i == n ) return 1;//边界条件,枚举出了一个满足条件的字符串
            if (!downlimit&&!uplimit&&memo[i][j]!= -1) //不受限且已经存储过,直接剪枝返回
                return memo[i][j];
            int res = 0; //计算个数
            char down = downlimit? s1[i]: 'a';// 根据受限与否决定枚举数下界
            char up = uplimit? s2[i] : 'z'; // 根据受限与否决定枚举数上界
            //做选择,因为每次移动要重新判断之前的字符串匹配到了哪一位,这里使用kmp算法,计算匹配失效转移位
            for (char c = down; c <= up; c++){
                int nextj = j-1;
                //对于枚举的字符,当前位不匹配,进行转移
                while(nextj!=-1&&evil[nextj+1]!=c) nextj = fail[nextj];
                //出循环再判断一次,因为nextj为-1后不会再判断移动
                if(evil[nextj+1]==c) nextj = nextj+1;
                res += f(i + 1, nextj + 1, downlimit&&c==down,uplimit&&c==up);//移动到下一位,判断限制情况
                res = res % MOD;//取模
            }

            if (!downlimit&&!uplimit) //记录非限制数
                memo[i][j] = res;
            return res;
        };
        return f(0,0,true,true);   //从下标0开始,刚开始受限
    }
};
posted @ 2023-06-08 03:38  失控D大白兔  阅读(31)  评论(0编辑  收藏  举报