• LeetCode 1397. Find All Good Strings 找到所有好字符串 (数位DP+KMP)


    好题… 就是比平时的 hard 难了一些……

    虽然猜出是数位DP了…不过比我之前做的题,好像多了一维,印象中都是一维记录之前状态就够了……然后就没做出……

    至于 KMP 的应用更是神奇,虽然掌握的 kmp 但是真的想不到……

    窝的代码能力太差了……总归是学到了……希望下次能做出来吧……

    参考题解 https://leetcode-cn.com/problems/find-all-good-strings/solution/shu-wei-dp-kmp-by-qodjf/ 

    国服现在好多大神…题解写的真的很棒~

    cal 计算小于等于任意字符串 s 的数目,计算两次求差就可了。其中 s1 没有被计算,所以单独算一次即可。

     dp[i][j][0]  前i个字符 和evil有j个相同 并且已经小于 S 证明后面的字符可以任意选择

     dp[i][j][1]  前i个字符 和evil有j个相同 并且等于 S 的前 i 个字符 所以后面的字符必须小于等于 S

    已知当前有 j 个字符和 evil 的前 j 个字符相等,下一个字符是 c ,则增加下一个字符之后有几个字符相等,这个就根据next数组的含义很容易计算。理解kmp应该都能懂。

    以上。

    class Solution {
    public:
        static const int mod = 1000000007;
        int findGoodStrings(int n, string s1, string s2, string evil) {
            int m = evil.size();
            int nt[m + 1];
            nt[0] = -1;
            for (int j = 0, k = -1; j < m; ) {
                if (k == -1 || evil[j] == evil[k]) nt[++j] = ++k;
                else k = nt[k];
            }
            int f = s1.find(evil) == string::npos;
            return (cal(n, s2, evil, nt) - cal(n, s1, evil, nt) + f + mod) % mod;
        }
        int cal(int n, string &s, string &evil, int nt[]) {
            int m = evil.size();
            int dp[n + 1][m][2];
            // dp[i][j][0] 前i个字符 和evil有j个相同 0不和s相等 1和s相等
            memset(dp, 0, sizeof dp);
            dp[0][0][1] = 1;
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    for (char c = 'a'; c <= 'z'; c++) {
                        int len = getNextLen(evil, nt, j, c);
                        if (len < m) {
                            if (c < s[i]) {
                                up(dp[i+1][len][0], dp[i][j][1]);
                            } 
                            if (c == s[i]) {
                                up(dp[i+1][len][1], dp[i][j][1]);
                            }
                            up(dp[i+1][len][0], dp[i][j][0]);
                        }
                    }
                }
            }
            int ans = 0;
            for (int i = 0; i < m; i++) {
                up(ans, dp[n][i][0]);
                up(ans, dp[n][i][1]);
            }
            return ans;
        }
        int getNextLen(string &evil, int nt[], int len, char c) {
            while (len != -1 && evil[len] != c) len = nt[len];
            return len + 1;
        }
        void up(int &x, int add) {
            x = (x + add) % mod;
        }
    };
  • 相关阅读:
    修改ssh默认端口
    网络配置
    nginx 反向代理
    nginx web 服务
    小白日记22:kali渗透测试之提权(二)--抓包嗅探
    小白日记21:kali渗透测试之提权(一)--本地提权
    小白日记20:kali渗透测试之后渗透测试阶段(一)--上传工具
    小白日记19:kali渗透测试之选择和修改EXP
    小白日记18:kali渗透测试之缓冲区溢出实例(二)--Linux,穿越火线1.9.0
    小白日记17:kali渗透测试之缓冲区溢出实例-windows,POP3,SLmail
  • 原文地址:https://www.cnblogs.com/wenruo/p/12616985.html
Copyright © 2020-2023  润新知