题目链接
思路分析
这个题在LC上属于hard类型,其实还是归结到了DP问题上。这个DP跟另外一题10. 正则表达式匹配有点像,但是这个题我个人来说做起来比正则表达式要简单很多。
这个题中,s和p都有可能为空,那么我们要先做个base cases。当两个字符串都为空的时候,直接返回true。但是当p为空的时候,我们才能返回false,因为如果s为空,p中只有的话,我们依然是可以匹配成功的(因为可以匹配空字符串)。
我们需要一个二维的boolean dp数组,其大小分别为[p.length()+1][s.length()+1],多出来的一个主要是为了处理空字符串的情形。它的含义是记录p(0 ~ i-1)和s(0 ~ j-1)的匹配结果。
dp[0][0]必定为true,因为两个空字符串肯定可以匹配。然后就是当s为空字符串的时候,我们要检测 如果当前字符为,并且它前一个字符匹配空字符串的情况为true的时候,dp[i][0]自然也为true,因为可以匹配空字符串。
在base cases做完之后,就开始正式的匹配了 ,我们匹配的原则有以下两点。
- 当s.charAt(i-1) == '?' 或者 s.charAt(i-1) == p.charAt(j-1)的时候,dp[i][j] = dp[i-1][j-1];
- 当s.charAt(i-1) == '*', dp[i][j] = dp[i-1][j] || dp[i][j-1];
第一个是因为?可以匹配任意一个字符,其实就和两个字符相等是一样的,我们直接去让他等于p(0 ~ i-1)和s(0 ~ j-1)的匹配结果就行。第二个遇到了,可以匹配空字符串或者任意字符串,那么我们的dp[i-1][j]就是匹配空字符串的情形,dp[i][j-1]就是匹配任意长度字符串。
最后我们返回dp[p.length()][s.length()]即可。
代码实现
class Solution {
public boolean isMatch(String s, String p) {
if(s.length() == 0 && p.length() == 0){
return true;
}
if(p.length() == 0){
return false;
}
boolean[][] dp = new boolean[p.length() + 1][s.length() + 1];
dp[0][0] = true;
for(int i = 1; i < dp.length; i++){
if(dp[i-1][0] && p.charAt(i-1) == '*'){
dp[i][0] = true;
}
}
for(int i = 1; i < dp.length; i++){
for(int j = 1; j < dp[i].length; j++){
if(p.charAt(i - 1) == '?' || p.charAt(i-1) == s.charAt(j-1)){
dp[i][j] = dp[i-1][j-1];
}else if(p.charAt(i-1) == '*'){
dp[i][j] = dp[i-1][j] || dp[i][j-1];
}
}
}
return dp[p.length()][s.length()];
}
}
总结
这个DP真的是要了我的老命,用了快一个小时才想出来,对于动态规划真的不够熟练。DP问题花样多还复杂,头疼。