题意:正则匹配。比较两个字符串是否一致,这里有两个特殊符号 “.” 和 “
∗
” ,”.”可以匹配单个字符,而”
分析:按照Solution中的思路,有递归和动态规划两种方法。而这道题使用动态规划不仅方便易懂,而且代码也非常整洁。首先看一下伪代码:
看起来很精简,但是要真正理解,我还是用了一下午的时间。下面我们从头开始说明一下构造dp二维数组的过程。
举例:
s = “aab”
p = “c*a*b”
要采用动态规划方法,肯定就是用空间换时间。那么我们申请一个二维数组dp:
boolean[][] dp = new boolean[s.length()+1][p.length()+1];
dp的初始化:
声明:下文中的索引都是从1开始,如p=c*a*b,那么p[0]=”,p[1]=’c’…..
首先,初始化第一列。只有dp[0][0] = True,dp[0][j]=False (j = 1,2,3)。因为对于p=”“来说,只有s=”“可以匹配到,其他的s匹配不到。
其次,初始化第一列。第一列的初始化就是对于s=”“来说,哪一个p能匹配到。对上图而言,当j=2和j=4时,能匹配到空字符。值得一提的是,在p中, ∗ 不能是第一个出现的字符,所以无需进行检查。
for (int i = 1; i <= p.length(); i++) {
if (p.charAt(i - 1) == '*') {
// * 不能是第一个出现的字符,所以无需进行检查
dp[0][i] = dp[0][i - 2];
}
}
dp的动态方程:
1、 对于特定的i和j,s和p中的字符能匹配。举例:s=abcd,p=abed,s[4]=p[4]=d,此时s和p是否匹配,就要看前面s[1]….s[3]=abc和p[1]…p[3]=abe是否匹配。此时满足的动态方程就是:
if(s.charAt(i - 1) == p.charAt(j - 1) || p.charAt(j - 1) == '.'){
dp[i][j] = dp[i - 1][j - 1];
}
2、对于特定的i和j,s和p中的字符不能匹配,即s[i]!=p[j]并且p[j]!=’.’。但是如果p[j]=
2.1、当p中
∗
前面的字母与p中的字母不匹配时,即s=abcd,p=abcde
if(s.charAt(i - 1) != p.charAt(j - 2) && p.charAt(j - 2) != '.'){
dp[i][j] = dp[i][j - 2];
}
2.2、当p中
2.2.1、
s=abcdd,p=abcd
∗
,s[5]=d,p[5]=
dp[i][j] = dp[i - 1][j]
2.2.2、
s=abcd,p=abcd
∗
,s[4]=d,p[5]=
dp[i][j] = dp[i][j - 1]
2.2.3、
s=abc,p=abc.
∗
,s[3]=c,p[5]=
dp[i][j] = dp[i][j - 2]
对于2.2.1、2.2.2、2.2.3三种情况只要满足一种即可。所以当p中 ∗ <script type="math/tex" id="MathJax-Element-1247">*</script>前面的字母与p中的字母匹配时:
dp[i][j] = dp[i - 1][j] || dp[i][j - 1] || dp[i][j - 2];
通过对上述逻辑的分析,填出dp初始化图中的空白部分应该也不在话下。感兴趣的同学可以自己加断点调试一下。所以总体的代码为:
//isMatch("aa","a") → false
//isMatch("aa","aa") → true
//isMatch("aaa","aa") → false
//isMatch("aa", "a*") → true
//isMatch("aa", ".*") → true
//isMatch("ab", ".*") → true
//isMatch("aab", "c*a*b") → true
class Solution {
public boolean isMatch(String s, String p){
if (s == null || p == null) {
return false;
}
boolean[][] dp = new boolean[s.length()+1][p.length()+1];
// 初始化 先初始化第一列
dp[0][0] = true;
// 在初始化第一行
for (int i = 1; i <= p.length(); i++) {
if (p.charAt(i - 1) == '*') {
// * 不能使第一个出现的字符,所以无需进行检查
dp[0][i] = dp[0][i - 2];
}
}
for (int i = 1 ; i <= s.length(); i++) {
for (int j = 1; j <= p.length(); j++) {
if(s.charAt(i - 1) == p.charAt(j - 1) || p.charAt(j - 1) == '.'){
dp[i][j] = dp[i - 1][j - 1];
}else if(p.charAt(j - 1) == '*'){
if(s.charAt(i - 1) != p.charAt(j - 2) && p.charAt(j - 2) != '.'){
dp[i][j] = dp[i][j - 2];
}else{
dp[i][j] = dp[i - 1][j] || dp[i][j - 1] || dp[i][j - 2];
}
}
}
}
return dp[s.length()][p.length()];
}
public static void main(String[] args) {
String s = "f";
String p = "f.*";
Solution sl = new Solution();
System.out.println(sl.isMatch(s, p));
}
}