思路:动态规划
当前的匹配结果由前面的匹配结果得出,所以需要建立一个二维数组来保存各个状态的结果。
根据两个字符串长度创建二维数组。(这里注意,需要将空字符状态也记录下来)
以用例 abcde 和 a.*f*d*e举例创建如下数组dp[][],T表示true F表示False
null | a | b | c | d | e | |
null | T | F | F | F | F | F |
a | F | T | F | f | f | f |
. | F | F | ||||
* | F | T | ||||
f | F | |||||
* | F | |||||
d | F | |||||
* | F | |||||
e | F |
已知条件: 匹配字符串s中的字符只包含字母,正则表达式字符串P包含字母,"."和"*".
所以分三种情况
情况1:字母和字母匹配
匹配结果:
1.1相等:dp[i][k] = dp[i-1][k-1]
1.2不相等:dp[i][k] = false
情况2:字母和'.'匹配
dp[i][k] = dp[i-1][k-1]
情况3:字母和'*'匹配 (重点在于情况三的处理)
如果遇到‘*’,那么'*'前面的字母(非‘.’字符,‘.’情况下面讨论)可以出现N次(N>=0)
如果N == 0,前面的字符一次也不出现
即 dp[i][k] = dp[i-2][k];
如果N >= 1 , 前面的字符肯定出现,那么s的末尾字母必须等于'*'前面的字母,否则肯定是false
即 p[i-1] != s[k] => dp[i][k] = false
如果相等的话(p[i-1] == s[k]) 比如 "####C" 和 "###C*"举例,当前的匹配结果等于"####"和"###C*"的匹配结果或者"####C"和"###C"的匹配结果,
即 dp[i][k] = dp[i][k-1] || dp[i-1][k]
所以我们对情况三做下归纳:
dp[i][k] = dp[i-2][k] || (p[i-1] == s[k] && dp[i][k-1])
最后将思路转化成代码。
public boolean isMatch(String s, String p) {
boolean dp[][] = new boolean[p.length() + 1][s.length() + 1];
for (int i = 0; i <= p.length(); i++) {
for (int k = 0; k <= s.length(); k++) {
if(i == 0 && k == 0) {
dp[i][k] = true;
} else if (i == 0) {
dp[i][k] = false;
} else if (k == 0) {
if(i >= 2 && p.charAt(i-1) == '*') {
dp[i][k] = dp[i-2][k];
} else {
dp[i][k] = false;
}
} else {
isTrue(dp, s, p, k, i);
}
}
}
return dp[p.length()][s.length()];
}
public void isTrue(boolean dp[][], String s, String p, int s_index, int p_index) {
int s_str_index = s_index - 1;
int p_str_index = p_index - 1;
if (p.charAt(p_str_index) != '.' && p.charAt(p_str_index) != '*') {
//情况1
if (s.charAt(s_str_index) == p.charAt(p_str_index)) {
dp[p_index][s_index] = dp[p_index - 1][s_index - 1];
} else {
dp[p_index][s_index] = false;
}
} else if (p.charAt(p_str_index) == '.') {
//情况2
dp[p_index][s_index] = dp[p_index - 1][s_index - 1];
} else {
//情况3
char preChar = p.charAt(p_str_index - 1);
boolean isMatch = preChar == '.' || preChar == s.charAt(s_str_index);
dp[p_index][s_index] = (p_index - 2 >= 0 && dp[p_index - 2][s_index]) || (isMatch && dp[p_index][s_index - 1]) || dp[p_index - 1][s_index];
}
}