Description
Given an input string (s) and a pattern §, implement regular expression matching with support for ‘.’ and ‘*’.
'.' Matches any single character.
'*' Matches zero or more of the preceding element.
The matching should cover the entire input string (not partial).
Note:
s could be empty and contains only lowercase letters a-z.
p could be empty and contains only lowercase letters a-z, and characters like . or *.
Example 1:
Input:
s = "aa"
p = "a"
Output:
false
Explanation:
"a" does not match the entire string "aa".
Example 2:
Input:
s = "aa"
p = "a*"
Output:
true
Explanation:
'*' means zero or more of the precedeng element, 'a'. Therefore, by repeating 'a' once, it becomes "aa".
Example 3:
Input:
s = "ab"
p = ".*"
Output:
true
Explanation:
".*" means "zero or more (*) of any character (.)".
Example 4:
Input:
s = "aab"
p = "c*a*b"
Output:
true
Explanation:
c can be repeated 0 times, a can be repeated 1 time. Therefore it matches "aab".
Example 5:
Input:
s = "mississippi"
p = "mis*is*p*."
Output:
false
分析
题目的意思是:
动态规划
dp[i][j]表示s[i-1]与p[j-1]是否匹配
如果 p[j-1] == s[i-1] || p[j-1] == ‘.’, 此时dp[i][j] = dp[i-1][j-1];
如果 p[j-1] == ‘*’
分两种情况:
1: 如果p[j-2] != s[i-1] && p[j-2] != ‘.’, 此时dp[i][j] = dp[i][j-2] //*前面字符匹配0次
2: 如果p[j-2] == s[i-1] || p[j-2] == ‘.’
此时dp[i][j] = dp[i][j-2] // *前面字符匹配0次
或者 dp[i][j] = dp[i][j-1] // *前面字符匹配1次
或者 dp[i][j] = dp[i-1][j] // *前面字符匹配多次
这题用递归的话,大致思路如下:
- 若p为空,s也为空,则返回true,否则返回false;
- 若p的长度为1,s的长度也为1,且相同或p为‘.’,则返回true,否则返回false;
- 若p的第二个字符不为*,此时s为空,则返回false,否则判断首字符是否匹配,且从各自的第二个字符开始调用递归函数;
- 若p的第二个字符为*,若s不空且字符匹配,调用递归函数s和去掉前两个字符的p,若匹配,则返回true,否则s去掉首字母;
- 返回调用递归函数匹配s和去掉前两个字符p的结果。
代码一 递归版本
class Solution {
public:
bool isMatch(string s, string p) {
if(p.empty()) return s.empty();
if(p.size()==1){
return s.size()==1&&(s[0]==p[0]||p[0]=='.');
}
if(p[1]!='*'){
if(s.empty()) return false;
return (s[0]==p[0]||p[0]=='.')&&isMatch(s.substr(1),p.substr(1));
}
while(!s.empty()&&(s[0]==p[0]||p[0]=='.')){
if(isMatch(s,p.substr(2))) return true;
s=s.substr(1);
}
return isMatch(s,p.substr(2));
}
};
代码二 动态规划版本
class Solution {
public:
bool isMatch(const char *s, const char *p) {
int m=strlen(s);
int n=strlen(p);
if(m==0&&n==0){
return true;
}
bool dp[m+1][n+1];
memset(dp,false,sizeof(dp));
dp[0][0]=true;
for(int i=1;i<=n;i++){
if(p[i-1]=='*'){
dp[0][i]=dp[0][i-2];
}
}
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
if(s[i-1]==p[j-1]||p[j-1]=='.'){
dp[i][j]=dp[i-1][j-1];
}else if(p[j-1]=='*'){
if(j!=1&&p[j-2]!='.'&&s[i-1]!=p[j-2]){
dp[i][j]=dp[i][j-2];
}else{
dp[i][j]=dp[i][j-1]||dp[i-1][j]||dp[i][j-2];
}
}
}
}
return dp[m][n];
}
};
Python实现
这个动态规划写出来要处理’.‘和’*'两种情况。
class Solution:
def isMatch(self, s: str, p: str) -> bool:
m = len(s)
n = len(p)
dp =[[False]*(n+1) for _ in range(m+1)]
dp[0][0]=True
for i in range(1,n+1):
if p[i-1]=="*":
dp[0][i]=dp[0][i-2]
for i in range(1, m+1):
for j in range(1, n+1):
if s[i-1]==p[j-1] or p[j-1]=='.':
dp[i][j]=dp[i-1][j-1]
elif p[j-1]=="*":
if j>1 and p[j-2]!='.' and s[i-1]!=p[j-2]:
dp[i][j]=dp[i][j-2]
else:
dp[i][j]=dp[i][j-1] or dp[i-1][j] or dp[i][j-2]
return dp[m][n]
参考文献
[编程题]regular-expression-matching
[LeetCode] Regular Expression Matching 正则表达式匹配