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;
    }
};

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章