https://leetcode-cn.com/problems/wildcard-matching/

  • 这题跟第10题有点像,但又不完全一样

    一个样本做行一个样本做列对应模型

    递归

    枚举行为
    image.png

    1. //递归
    2. public boolean isMatch(String str, String pattern) {
    3. char[] s = str.toCharArray();
    4. char[] p = pattern.toCharArray();
    5. return process(s, p, 0, 0);
    6. }
    7. //s[si....] 能否与 p[pi.....] 匹配
    8. private boolean process(char[] s, char[] p, int si, int pi) {
    9. if (si == s.length) { // si到终点了
    10. if (pi == p.length) { //pi也到终点
    11. return true;
    12. } else {
    13. return p[pi] == '*' && process(s, p, si, pi + 1);
    14. }
    15. }
    16. // si != s.length
    17. if (pi == p.length) {
    18. return false;
    19. }
    20. if (p[pi] != '?' && p[pi] != '*') {
    21. return s[si] == p[pi] && process(s, p, si + 1, pi + 1);
    22. }
    23. if (p[pi] == '?') {
    24. return process(s, p, si + 1, pi + 1);
    25. }
    26. // p[pi] == '*'
    27. // 枚举行为: * 匹配 s[si...si]
    28. // * 匹配 s[si...si + 1]
    29. // * 匹配 s[si...si + 2]
    30. // .........
    31. for (int len = 0; len <= s.length - si; len++) {
    32. if (process(s, p, si + len, pi + 1)) {
    33. return true;
    34. }
    35. }
    36. return false;
    37. }

递归改动态规划

  1. public boolean isMatch2(String str, String pattern) {
  2. char[] s = str.toCharArray();
  3. char[] p = pattern.toCharArray();
  4. int N = s.length;
  5. int M = p.length;
  6. boolean[][] dp = new boolean[N + 1][M + 1];
  7. dp[N][M] = true;
  8. for (int pi = M - 1; pi >= 0; pi--) {
  9. dp[N][pi] = p[pi] == '*' && dp[N][pi + 1];
  10. }
  11. for (int si = N - 1; si >= 0; si--) {
  12. for (int pi = M - 1; pi >= 0; pi--) {
  13. if (p[pi] != '?' && p[pi] != '*') {
  14. dp[si][pi] = s[si] == p[pi] && dp[si + 1][pi + 1];
  15. continue;
  16. }
  17. if (p[pi] == '?') {
  18. dp[si][pi] = dp[si + 1][pi + 1];
  19. continue;
  20. }
  21. // p[pi] == '*'
  22. for (int len = 0; len <= s.length - si; len++) {
  23. if (dp[si + len][pi + 1]) {
  24. dp[si][pi] = true;
  25. break;
  26. }
  27. }
  28. }
  29. }
  30. return dp[0][0];
  31. }

斜率优化

有枚举行为(pi位置字符是* 的时候)
image.png
观察临近的格子看能不能把枚举行为省掉
image.png
(4,8)位置的值与(5,7)位置的值或,就可以了

  1. public boolean isMatch3(String str, String pattern) {
  2. char[] s = str.toCharArray();
  3. char[] p = pattern.toCharArray();
  4. int N = s.length;
  5. int M = p.length;
  6. boolean[][] dp = new boolean[N + 1][M + 1];
  7. dp[N][M] = true;
  8. for (int pi = M - 1; pi >= 0; pi--) {
  9. dp[N][pi] = p[pi] == '*' && dp[N][pi + 1];
  10. }
  11. for (int si = N - 1; si >= 0; si--) {
  12. for (int pi = M - 1; pi >= 0; pi--) {
  13. if (p[pi] != '?' && p[pi] != '*') {
  14. dp[si][pi] = s[si] == p[pi] && dp[si + 1][pi + 1];
  15. continue;
  16. }
  17. if (p[pi] == '?') {
  18. dp[si][pi] = dp[si + 1][pi + 1];
  19. continue;
  20. }
  21. // p[pi] == '*'
  22. dp[si][pi] = dp[si][pi + 1] || dp[si + 1][pi];
  23. }
  24. }
  25. return dp[0][0];
  26. }