题目
给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 ‘.’ 和 ‘*’ 的正则表达式匹配。
‘.’ 匹配任意单个字符
‘*’ 匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。
代码
class Solution {
HashMap<String,Boolean> memo;
public boolean isMatch(String s, String p) {
memo =new HashMap<>();
// 指针 i,j 从索引 0 开始移动
return dp(s,0,p,0);
}
boolean dp(String s,int i,String p, int j){//i,j之后能否匹配
int m=s.length(),n=p.length();
// base case
if (j==n) return i==m;
if (i==m){
if ((n-j)%2==1) return false;//之后p要以b*c*这种形式才行,如果能匹配空串,一定是字符和 * 成对儿出现
// 检查是否为 x*y*z* 这种形式
for (; j<n; j+=2) {
if (p.charAt(j+1)!='*') return false;
}
return true;
}
// 记录状态 (i, j),消除重叠子问题
String k = i+","+j ;
if (memo.containsKey(k)) return memo.get(k);
boolean res =false;
if (s.charAt(i)==p.charAt(j)||p.charAt(j)=='.'){
// 匹配
if (j<n-1&&p.charAt(j+1)=='*'){//若果后面跟着*,要作其他打算
// 1.1 通配符匹配 0 次或多次
res= dp(s,i,p,j+2)||dp(s,i+1,p,j);//前面是0次,后面是1次以上
}else {
// 1.2 常规匹配 1 次
res= dp(s,i+1,p,j+1);
}
}else {
// 不匹配的情况
if (j<n-1 && p.charAt(j+1)=='*'){//若后面有*能续命
// 2.1 通配符匹配 0 次
res= dp(s,i,p,j+2);
}else {//寄了
res= false;
}
}
//加入备忘录
memo.put(k,res);
return res;
}
}
要点
- 由于.和* 的特殊匹配方式,所以需要逐个分析,并利用动态规划进行遍历
- 在判断是否匹配结束的时候,也需要进行分析,不能简单的判断是否结束
- 使用哈希表来消除重复子问题