7. LeetCode 10:正则表达式匹配
给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 ‘.’ 和 ‘*’ 的正则表达式匹配。
‘.’ 匹配任意单个字符
‘*’ 匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。说明:
s 可能为空,且只包含从 a-z 的小写字母。
p 可能为空,且只包含从 a-z 的小写字母,以及字符 . 和 *。
解析:
方法一:递归解决
只考虑s,p的第一个字符:
-
若p为空,只有s也为空时匹配;
-
若第一个字符匹配,
- 若p的第二个字符不为’*’,递归调用isMath(s.substring(1),p.substring(1))。
- 若p的第二个字符为’*’,考虑匹配的字符是否存在多个或根本不存在,isMatch(s,p.substring(2))或isMatch(s.substring(1),p);
-
若第一个字符不匹配,
- 若p的第二个字符不为’*’,false
- 若p的第二个字符为’*’,p(0)不在s中,isMatch(s,p.substring(2))
代码(转化为数组速度更快):
public boolean isMatch(String s, String p) {
if(p.isEmpty()){return s.isEmpty();}
return isMatch(s.toCharArray(),0,p.toCharArray(),0);
}
public boolean isMatch(char[] s, int i,char[] p,int j){
if(j>=p.length){return i>=s.length;}
if(i<s.length&&(p[j]==s[i]||p[j]=='.')){
if(j+1<p.length&&p[j+1]=='*'){
return isMatch(s,i,p,j+2)||isMatch(s,i+1,p,j);
}else{
return isMatch(s,i+1,p,j+1);
}
}else{
if(j+1<p.length&&p[j+1]=='*'){
return isMatch(s,i,p,j+2);
}else{
return false;
}
}
}
方法二:动态规划
考虑到第一种解法中大量使用i,j后面的结果,考虑动态规划
从后往前找,可以用填表的方法找思路
class Solution {
public boolean isMatch(String text, String pattern) {
boolean[][] dp = new boolean[text.length() + 1][pattern.length() + 1];
dp[text.length()][pattern.length()] = true;
for (int i = text.length(); i >= 0; i--){
for (int j = pattern.length() - 1; j >= 0; j--){
boolean first_match = (i < text.length() &&
(pattern.charAt(j) == text.charAt(i) ||
pattern.charAt(j) == '.'));
if (j + 1 < pattern.length() && pattern.charAt(j+1) == '*'){
dp[i][j] = dp[i][j+2] || first_match && dp[i+1][j];
} else {
dp[i][j] = first_match && dp[i+1][j+1];
}
}
}
return dp[0][0];
}
}