请实现一个函数用来匹配包括'.'
和'*'
的正则表达式。
模式中的字符'.'
表示任意一个字符,而'*'
表示它前面的字符可以出现任意次(含0次)。
在本题中,匹配是指字符串的所有字符匹配整个模式。
例如,字符串"aaa"
与模式"a.a"
和"ab*ac*a"
匹配,但是与"aa.a"
和"ab*a"
均不匹配。
样例
输入:
s="aa"
p="a*"
输出:true
思路:
递归
判断多种情况。如果模式串中有星号,它会出现在第二个位置,即pattern[1] 。这种情况下,我们可以直接忽略模式串中这一部分,或者删除匹配串的第一个字符,前提是它能够匹配模式串当前位置字符,即pattern[0] 。如果两种操作中有任何一种使得剩下的字符串能匹配,那么初始时,匹配串和模式串就可以被匹配。
class Solution {
public boolean isMatch(String s, String p) {
if(p.isEmpty()) return s.isEmpty();
boolean first_match = (!s.isEmpty() &&
(p.charAt(0) == s.charAt(0) || p.charAt(0) == '.'));
// 如果第二个字母为‘*’的情况, 有3种情况
// 1:s,p+2; 2:s+1,p+2; 3:s+1,p;
if(p.length() >= 2 && p.charAt(1) == '*'){
// 此处先判断 s 是否和 p + 2 匹配,若不匹配,则 s,p+2; s+1,p+2 不用再判断
return (isMatch(s, p.substring(2)) ||
(first_match && isMatch(s.substring(1), p)));
}else{
return first_match && isMatch(s.substring(1), p.substring(1));
}
}
}
动态规划
我们用 [方法 1] 中同样的回溯方法,除此之外,因为函数 match(text[i:], pattern[j:]) 只会被调用一次,我们用dp(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];
}
}