@@ -23,71 +23,91 @@ isMatch("ab", ".*") → true
2323isMatch("aab", "c*a*b") → true
2424```
2525
26- ** Tags:** String, Dynamic Programmin , Backtracking
26+ ** Tags:** String, Dynamic Programming , Backtracking
2727
2828
2929## 思路0
3030
31- 题意是
32-
31+ 题意是让让你从判断` s ` 字符串是否正则匹配于` p ` ,这道题和[ Wildcard Matching] [ 044 ] 很是相似,区别在于` * ` ,通配符的` * ` 是可以随意出现的,跟前面字符没有任何关系,其作用是可以表示任意字符串;而正则匹配的` * ` 不能单独存在,前面必须具有一个字符,其意义是表明前面的这个字符个数可以是任意个数,包括0个。首先我们用递归的方式来实现,其思路如下:
32+ * 如果` s ` 和` p ` 都为空,那么返回` true `
33+ * 如果` p ` 的长度为1,当` s ` 的长度也为1,并且他们首位匹配则返回` true ` ,否则返回` false `
34+ * 如果` p ` 的第二个字符不为'* ',如果` s ` 为空,那就返回` false ` ,首位匹配则返回递归调用他们去掉首位的子字符串,否则返回` false `
35+ * 如果` p ` 的第二个字符为'* ',循环当` s ` 不为空,且首位匹配,如果递归调用是否匹配` s ` 字符串和` p ` 去掉前两位的子字符串,则返回` true ` ,否则` s ` 去掉首字母继续循环
36+ * 返回递归调用` s ` 字符串和` p ` 去掉前两位的子字符串是否匹配
3337
3438``` java
3539class Solution {
3640 public boolean isMatch (String s , String p ) {
37- if (p. length() == 0 ) return s. length() == 0 ;
41+ if (p. isEmpty() ) return s. isEmpty() ;
3842 if (p. length() == 1 ) {
39- if (s. length() < 1 ) return false ;
40- if (p. charAt(0 ) != s. charAt(0 ) && p. charAt(0 ) != ' .' ) return false ;
41- return true ;
43+ return s. length() == 1 && (p. charAt(0 ) == s. charAt(0 ) || p. charAt(0 ) == ' .' );
4244 }
4345 if (p. charAt(1 ) != ' *' ) {
44- if (s. length() < 1 ) return false ;
45- if (p. charAt(0 ) != s. charAt(0 ) && p. charAt(0 ) != ' .' ) return false ;
46- return isMatch(s. substring(1 ), p. substring(1 ));
47- } else {
48- // match 0 preceding element
46+ if (s. isEmpty()) return false ;
47+ return (p. charAt(0 ) == s. charAt(0 ) || p. charAt(0 ) == ' .' )
48+ && isMatch(s. substring(1 ), p. substring(1 ));
49+ }
50+ // match 1 or more preceding element
51+ while (! s. isEmpty() && (p. charAt(0 ) == s. charAt(0 ) || p. charAt(0 ) == ' .' )) {
4952 if (isMatch(s, p. substring(2 ))) return true ;
50- int i = 0 ;
51- // match 1 or more preceding element
52- while (i < s. length() && (p. charAt(0 ) == s. charAt(i) || p. charAt(0 ) == ' .' )) {
53- if (isMatch(s. substring(i + 1 ), p. substring(2 ))) {
54- return true ;
55- }
56- ++ i;
57- return false ;
58- }
53+ s = s. substring(1 );
54+ }
55+ // match 0 preceding element
56+ return isMatch(s, p. substring(2 ));
57+ }
58+ }
59+ ```
60+
61+
62+ ## 思路1
63+
64+ 我们可以把上面的思路更简单化,如下
65+ * 如果` s ` 和` p ` 都为空,那么返回` true `
66+ * 如果` p ` 的第二个字符为` * ` ,由于` * ` 前面的字符个数可以为任意,那么我们先递归调用个数为0的情况;或者当` s ` 不为空,如果他们的首字母匹配,那么我们就递归调用去掉去掉首字母的` s ` 和完整的` p `
67+ * 如果` p ` 的第二个字符不为` * ` ,那么我们就老老实实判断第一个字符是否匹配并且递归调用他们去掉首位的子字符串
68+
69+ ``` java
70+ class Solution {
71+ public boolean isMatch (String s , String p ) {
72+ if (p. isEmpty()) return s. isEmpty();
73+ if (p. length() > 1 && p. charAt(1 ) == ' *' ) {
74+ return isMatch(s, p. substring(2 ))
75+ || (! s. isEmpty() && (p. charAt(0 ) == s. charAt(0 ) || p. charAt(0 ) == ' .' )
76+ && isMatch(s. substring(1 ), p));
5977 }
78+ return ! s. isEmpty() && (p. charAt(0 ) == s. charAt(0 ) || p. charAt(0 ) == ' .' )
79+ && isMatch(s. substring(1 ), p. substring(1 ));
6080 }
6181}
6282```
6383
84+ ## 思路2
85+
86+ 另一种思路就是动态规划了,我们定义` dp[i][j] ` 的真假来表示` s[0..i) ` 是否匹配` p[0..j) ` ,通过思路1,我们可以确定其状态转移方程如下所示:
87+ * 如果` p[j - 1] == '*' ` , ` dp[i][j] = dp[i][j - 2] || (pc[j - 2] == sc[i - 1] || pc[j - 2] == '.') && dp[i - 1][j]; `
88+ * 如果` p[j - 1] != '*' ` ,` dp[i][j] = dp[i - 1][j - 1] && (pc[j - 1] == '.' || pc[j - 1] == sc[i - 1]); `
89+
90+
6491
6592``` java
6693class Solution {
6794 public boolean isMatch (String s , String p ) {
6895 if (p. length() == 0 ) return s. length() == 0 ;
69- if (p. contains(" .*" )) return true ;
7096 int sL = s. length(), pL = p. length();
7197 boolean [][] dp = new boolean [sL + 1 ][pL + 1 ];
98+ char [] sc = s. toCharArray(), pc = p. toCharArray();
7299 dp[0 ][0 ] = true ;
73- for (int i = 1 ; i < pL; ++ i) {
74- if (p . charAt(i) == ' *' && dp[0 ][i - 1 ]) {
75- dp[0 ][i + 1 ] = true ;
100+ for (int i = 2 ; i <= pL; ++ i) {
101+ if (pc[i - 1 ] == ' *' && dp[0 ][i - 2 ]) {
102+ dp[0 ][i] = true ;
76103 }
77104 }
78- for (int i = 0 ; i < sL; ++ i) {
79- for (int j = 0 ; j < pL; ++ j) {
80- char c1 = s. charAt(i), c2 = p. charAt(j);
81- if (c2 == ' .' || c2 == c1) {
82- dp[i + 1 ][j + 1 ] = dp[i][j];
83- }
84- if (c2 == ' *' ) {
85- c2 = p. charAt(j - 1 );
86- if (c2 == c1 || c2 == ' .' ) {
87- dp[i + 1 ][j + 1 ] = dp[i + 1 ][j] || dp[i][j + 1 ] || dp[i + 1 ][j - 1 ];
88- } else {
89- dp[i + 1 ][j + 1 ] = dp[i + 1 ][j - 1 ];
90- }
105+ for (int i = 1 ; i <= sL; ++ i) {
106+ for (int j = 1 ; j <= pL; ++ j) {
107+ if (pc[j - 1 ] == ' *' ) {
108+ dp[i][j] = dp[i][j - 2 ] || (pc[j - 2 ] == sc[i - 1 ] || pc[j - 2 ] == ' .' ) && dp[i - 1 ][j];
109+ } else {
110+ dp[i][j] = dp[i - 1 ][j - 1 ] && (pc[j - 1 ] == ' .' || pc[j - 1 ] == sc[i - 1 ]);
91111 }
92112 }
93113 }
@@ -103,5 +123,6 @@ class Solution {
103123
104124
105125
126+ [ 044 ] : https://github.com/Blankj/awesome-java-leetcode/blob/master/note/044/README.md
106127[ title ] : https://leetcode.com/problems/regular-expression-matching
107128[ ajl ] : https://github.com/Blankj/awesome-java-leetcode
0 commit comments