解题思路:
这道题的意思就是字符串匹配,s是正常的字符串,p是带有特殊字符的字符串,在p中,’?‘可以匹配任意一个字符,’*'可以匹配任意长度(包括0)的字符。
这道题可以用DP来做。(初始答案在题目后面的Description里)
首先动态规划的特点是会求得所有过程中的结果。
具体做法:
设s=adceb p=* a* b 我们先创建一个boolean二维数组match,行数为s.length+1,用于存放s字符串;宽为p.length+1,用于存放p字符串;
数组中任意一个value的值表示的是当前行及以下的s和当前列及以后的p的字符串是否匹配,如果两个方框所示。所以这里DP的方法是从尾匹配到头;
现在说明匹配过程:
首先match[s.length][p.length]=true
然后对于最后一排,满足:
if(p.charAt(i)==’*’)
match[s.length()][i]=true;
就是最后一排,从后到前开始算,遇到p字符串的内容是’*'的话,值是true,这里p字符串的后面没有 ’ * ',所以最后一排的其他数值不做处理,直接跳到倒数第二行。
对于剩下的部分,只对中间部分进行计算,最后一列不做处理:
对于中间部分处理的顺序是,从最后一排的尾处理到头、从倒数第二排的尾处理到头、…
对于这些内容,处理的规则是:
if(s.charAt(i)==p.charAt(j)||p.charAt(j)=='?')
match[i][j]=match[i+1][j+1];
else if(p.charAt(j)=='*')
match[i][j]=match[i+1][j]||match[i][j+1];
else
match[i][j]=false;
即分为三种情况,第一种:s[i]和p[j]字符是相同的
此时3处的数值match[i][j]取决于右下方的数值match[i+1][j+1]:
第二种,p[j]==’*’:
此时只要match[i][j]的右边是true或者下边是true,自己就是true:
第三种情况,s[i]!=p[j]:
直接false
根据这个规则可以填满所有的地方:
* | a | * | b | - | |
---|---|---|---|---|---|
a | true | true | true | false | |
d | false | false | true | false | |
c | false | false | true | false | |
e | false | false | true | false | |
b | false | false | true | true | |
- | true |
同时,match[0][0]就是最终的答案:
这个过程其实将所有过程中的答案都给了出来,符合DP的特点,比如下图中:
这个值的意思是" c e b “和” * b "字符串是匹配的
这个值表示"dceb"和"* a* b"是不匹配的
提交代码:
class Solution{
public boolean isMatch(String s, String p) {
boolean match[][]=new boolean[s.length()+1][p.length()+1];
match[s.length()][p.length()]=true;
for(int i=p.length()-1;i>=0;i--) {
if(p.charAt(i)=='*')
match[s.length()][i]=true;
else break;
}
for(int i=s.length()-1;i>=0;i--) {
for(int j=p.length()-1;j>=0;j--) {
if(s.charAt(i)==p.charAt(j)||p.charAt(j)=='?')
match[i][j]=match[i+1][j+1];
else if(p.charAt(j)=='*')
match[i][j]=match[i+1][j]||match[i][j+1];
else
match[i][j]=false;
}
}
return match[0][0];
}
}
运行结果: