分析:整理K神题解,加了注释

    • 状态数组:设二维数组dp[m+1][n+1],m和n是s、p的长度
      • 特殊说明:dp[i][j]表示s下标为s[i-1]的字符,p下标为p[j-1]字符
    • 初始化: dp[i][j] 表示 s的前i个字符和p的前j个字符是否匹配
      • dp[0][0]=true,表示s和p的前0个字符均为空串肯定匹配
      • 若s是空串且p 的偶数次下标为$*$,那也是匹配的
    • 状态转移:
      • p.charAt(j - 1) == ‘*’,有三种情况匹配
        • dp[i][j - 2],既是p[j-2]出现0次
        • (dp[i - 1][j] && s.charAt(i - 1) == p.charAt(j - 2),p[j-2]出现1次 且 当前i-1和j-2指向的字符相同
        • dp[i - 1][j] && p.charAt(j - 2) == ‘.’,最特殊情况:p[j-2]=. p[j-1]=*时,根据条件知是万能匹配
      • p.charAt(j - 1) != ‘*’,有两种情况匹配
        • dp[i - 1][j - 1] && s.charAt(i - 1) == p.charAt(j - 1),前面元素之前都匹配 且 当前元素也相容
        • dp[i - 1][j - 1] && p.charAt(j - 1) == ‘.’,前面元素之前都匹配 且 p的当期元素是.
    • 返回值:dp[m][n]

      1. public class Solution {
      2. // 最直观版
      3. public boolean isMatch(String s, String p) {
      4. int m = s.length();
      5. int n = p.length();
      6. // dp[i][j]表示s前i-1个字符,p前j-1个字符是否匹配
      7. boolean[][] dp = new boolean[m + 1][n + 1];
      8. // dp[0][0] :s前0个字符和p的前0个字符默认是空串=匹配
      9. // 注意:由于多了[0][0],所以dp[i][j],定位到的是s[i-1]和p[j-1]的字符
      10. dp[0][0] = true;
      11. // 初始化首行:当s为空串,p的偶数位为*才能匹配
      12. for (int j = 2; j < n + 1; j += 2) {
      13. dp[0][j] = dp[0][j - 2] && p.charAt(j - 1) == '*';
      14. }
      15. // 状态转移
      16. for (int i = 1; i < m + 1; i++) {
      17. for (int j = 1; j < n + 1; j++) {
      18. // 当p[j-1]=*时,有三种情况
      19. if (p.charAt(j - 1) == '*') {
      20. if (dp[i][j - 2]) {// p[j-2]出现0次,i和j指向字符的长度均相同
      21. dp[i][j] = true;
      22. } else if (dp[i - 1][j] && s.charAt(i - 1) == p.charAt(j - 2)) {// p[j-2]出现1次 且 当前i-1和j-2指向的字符相同
      23. dp[i][j] = true;
      24. } else if (dp[i - 1][j] && p.charAt(j - 2) == '.') {// 最特殊情况:p[j-2]=. p[j-1]=*时 是万能匹配
      25. dp[i][j] = true;
      26. }
      27. } else {// 当p[j-1]!=*时,有两种情况
      28. if (dp[i - 1][j - 1] && s.charAt(i - 1) == p.charAt(j - 1)) {// 前面元素之前都匹配 且 当前元素也相容
      29. dp[i][j] = true;
      30. } else if (dp[i - 1][j - 1] && p.charAt(j - 1) == '.') { // 前面元素之前都匹配 且 p的当期元素是.
      31. dp[i][j] = true;
      32. }
      33. }
      34. }
      35. }
      36. return dp[m][n];
      37. }
      38. // 用三目运算符优化使代码更美观,更快
      39. public boolean isMatch1(String s, String p) {
      40. int m = s.length();
      41. int n = p.length();
      42. // dp[i][j]表示s前i-1个字符,p前j-1个字符是否匹配
      43. boolean[][] dp = new boolean[m + 1][n + 1];
      44. // dp[0][0] :s前0个字符和p的前0个字符默认是空串=匹配
      45. // 注意:由于多了[0][0],所以dp[i][j],定位到的是s[i-1]和p[j-1]的字符
      46. dp[0][0] = true;
      47. // 初始化首行:当s为空串,p的偶数位为*才能匹配
      48. for (int j = 2; j < n + 1; j += 2) {
      49. dp[0][j] = dp[0][j - 2] && p.charAt(j - 1) == '*';
      50. }
      51. // 状态转移
      52. for (int i = 1; i < m + 1; i++) {
      53. for (int j = 1; j < n + 1; j++) {
      54. dp[i][j] = p.charAt(j - 1) == '*' ?
      55. dp[i][j - 2] || dp[i - 1][j] && (s.charAt(i - 1) == p.charAt(j - 2) || p.charAt(j - 2) == '.') :
      56. dp[i - 1][j - 1] && (p.charAt(j - 1) == '.' || s.charAt(i - 1) == p.charAt(j - 1));
      57. }
      58. }
      59. return dp[m][n];
      60. }
      61. }