leetcode-182周赛-5371. 找到所有好字符串

 题目描述:

 

 python 回溯 +kmp next数组

class Solution:
    def findGoodStrings(self, n: int, s1: str, s2: str, evil: str) -> int:
        
        
        MOD = int(1e9 + 7)
        m = len(evil)
        orda = ord('a')
        ordz = ord('z')
        
        nxt = [-1] * (m + 1)
        i = 0
        j = -1
        while i < m:
            if j == -1 or evil[i] == evil[j]:
                i += 1
                j += 1
                nxt[i] = j
            else:
                j = nxt[j]
        # print(nxt)
        
        from functools import lru_cache
        
        @lru_cache(None)
        def dfs(idx, reach1, reach2, match):
            if match == m - 1: return 0
            if idx == n:
                return 1
        
            s = ord(s1[idx])
            e = ord(s2[idx])
            res = 0
            lim1 = s if reach1 else orda
            lim2 = e + 1 if reach2 else ordz + 1
            for i in range(lim1, lim2):
                ch = chr(i)
                if ch == evil[match + 1]:
                    nxtmat = match + 1
                else:
                    nxtmat = match + 1
                    while nxtmat != -1 and ch != evil[nxtmat]:
                        nxtmat = nxt[nxtmat]
                res += dfs(idx + 1, reach1 and i == s, reach2  and i == e, nxtmat)
            return res % MOD
        
        
        return dfs(0, True, True, -1)

java dp

// time complxity O(n * m * m * 26)
class Solution {

  public int findGoodStrings(int n, String s1, String s2, String evil) {
    int mod = (int) 1e9 + 7;
    int m = evil.length();
    long[][][] dp = new long[n + 1][4][m + 1]; // 第二维度中, 0表示s1和s2都有限制,1表s1有限制, 2表示s2有限制, 3表示s1和s2无限制; 第三维度表示前面已经匹配的evil的长度
    // 初始化
    for (int i = 0; i < m; i++) {
      dp[n][0][i] = 1;
      dp[n][1][i] = 1;
      dp[n][2][i] = 1;
      dp[n][3][i] = 1;
    }
    char[] p = evil.toCharArray();
    int[] prefix = calcuPrefixFunction(p); // O(n),计算前缀数组
    for (int i = n - 1; i >= 0; i--) {
      for (int j = 0; j < m; j++) {
        // handle 0
        for (char k = s1.charAt(i); k <= s2.charAt(i); k++) {
          int state = 0;
          if (k == s1.charAt(i) && k == s2.charAt(i)) {
            state = 0;
          } else if (k == s1.charAt(i)) {
            state = 1;
          } else if (k == s2.charAt(i)) {
            state = 2;
          } else {
            state = 3;
          }
          dp[i][0][j] += dp[i + 1][state][getNext(prefix, p, k, j)];
          dp[i][0][j] %= mod;
        }
        // handle 1
        for (char k = s1.charAt(i); k <= 'z'; k++) {
          int state = k == s1.charAt(i) ? 1 : 3;
          dp[i][1][j] += dp[i + 1][state][getNext(prefix, p, k, j)];
          dp[i][1][j] %= mod;
        }
        //handle 2
        for (char k = 'a'; k <= s2.charAt(i); k++) {
          int state = k == s2.charAt(i) ? 2 : 3;
          dp[i][2][j] += dp[i + 1][state][getNext(prefix, p, k, j)];
          dp[i][2][j] %= mod;
        }
        // handle 3
        for (char k = 'a'; k <= 'z'; k++) {
          int state = 3;
          dp[i][3][j] += dp[i + 1][state][getNext(prefix, p, k, j)];
          dp[i][3][j] %= mod;
        }
      }
    }
    return (int) dp[0][0][0];
  }

  private int[] calcuPrefixFunction(char[] p) { // 考虑边界情况, 即p的长度为0
    int n = p.length;
    int[] prefixArray = new int[n];  // 表示匹配的长度结果
    prefixArray[0] = 0;
    int j = 0;  // len of match string 表示匹配的长度
    for (int i = 1; i < n; i++) {
      while (j > 0 && p[i] != p[j]) {
        j = prefixArray[j - 1];
      }
      if (p[i] == p[j]) {
        j++;
      }
      prefixArray[i] = j;
    }
    return prefixArray;
  }

  private int getNext(int[] prefix, char[] p, char c, int j) {
    while (j > 0 && c != p[j]) {
      j = prefix[j - 1];
    }
    if (c == p[j]) {
      j++;
    }
    return j;
  }
}

 

posted @ 2020-03-30 16:15  oldby  阅读(200)  评论(0编辑  收藏  举报