10. 正则表达式匹配(困难)
给你一个字符串 s
和一个字符规律 p
,请你来实现一个支持 '.'
和 '*'
的正则表达式匹配。
'.'
匹配任意单个字符'*'
匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖 整个 字符串 s
的,而不是部分字符串。
示例 1:
输入:s = "aa" p = "a"
输出:false
解释:"a" 无法匹配 "aa" 整个字符串。
示例 2:
输入:s = "aa" p = "a*"
输出:true
解释:因为 '*' 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 'a'。因此,字符串 "aa" 可被视为 'a' 重复了一次。
示例 3:
输入:s = "ab" p = ".*"
输出:true
解释:".*" 表示可匹配零个或多个('*')任意字符('.')。
示例 4:
输入:s = "aab" p = "c*a*b"
输出:true
解释:因为 '*' 表示零个或多个,这里 'c' 为 0 个, 'a' 被重复一次。因此可以匹配字符串 "aab"。
示例 5:
输入:s = "mississippi" p = "mis*is*p*."
输出:false
思路:
-
从后往前匹配:
设置指针
i=s.length-1,j=p.length-1
。从后往前匹配,- 当
p[j]==s[i]
时,s与p是否匹配取决于s[0:i-1]与p[0:j-1]
是否匹配(s的前i个字符与p的前j个字符是否匹配) - 当
p[j]=='.'
时可以匹配任一个字符,因此此时s与p是否匹配取决于s[0:i-1]与p[0:j-1]
是否匹配 - 当
p[j]=='*'
时,由于'*'
可以匹配零个或多个前面的那一个元素,需要分情况讨论p[j-1]==s[i]或p[j-1]=='.'
,此时'*'
可以表示为匹配一个或多个前一个字符,即此时s与p是否匹配取决于s[0:i-1]与p[0:j]
是否匹配;此外,'*'
也可以表示为匹配0个前一个字符(这是由于从后往前匹配,会出现虽然p[j-1]==s[i],但从前往后匹配时s[i]匹配的为p[i-2]的字符),因此s与p是否匹配也取决于s[0:i]与p[0:j-2]
是否匹配.p[j-1]
为其他值时,'*'
表示为匹配0个前一个字符,因此s与p是否匹配也取决于s[0:i]与p[0:j-2]
是否匹配.。
- 当
p[j]
为其他值时,s与p不匹配。
注意:
(1)在3.1中两种情况为
or
的关系,只要一种情况匹配,s[0:i]与p[0:j]
即匹配。因此 不能采用迭代来写代码,只能采用递归。(2)注意边界条件的判断
i=-1,j>=0
:此时需要看p[0:j]
的情况,若p[0:j]
中均是('a-z'/'.'+'*')
的组合则匹配,否则不匹配。i>=0,j=-1
:说明s与p不匹配(s多出来一部分),返回falsei=-1,j=-1
:此时说明s与p匹配,返回True
- 当
-
从前往后匹配(动态规划)
设置动态规划数组d[i][j]
表示s的前i个与p的前j个字符的匹配结果
p[j]==s[i]
:s与p是否匹配取决于s[0:i-1]与p[0:j-1]
是否匹配,因此du[i][j]=d[i-1][j-1]
.p[j]=='.'
:s与p是否匹配取决于s[0:i-1]与p[0:j-1]
是否匹配,因此du[i][j]=d[i-1][j-1]
.p[j]=='*'
:由于'*'
可以匹配零个或多个前面的那一个元素,需要分情况讨论p[j-1]==s[i]或p[j-1]=='.'
,此时'*'
可以表示为匹配一个或多个前一个字符,即此时s与p是否匹配取决于s[0:i-1]与p[0:j]
是否匹配,即d[i][j]=d[i-1][j]
;此外,'*'
也可以表示为匹配0个前一个字符(这是由于从后往前匹配,会出现虽然p[j-1]==s[i],但从前往后匹配时s[i]匹配的为p[i-2]的字符),因此s与p是否匹配也取决于s[0:i]与p[0:j-2]
是否匹配,即d[i][j]=d[i][j-2]
.p[j-1]
为其他值时,'*'
表示为匹配0个前一个字符,因此s与p是否匹配也取决于s[0:i]与p[0:j-2]
是否匹配,即d[i][j]=d[i][j-2]
.
- 其他情况时,
d[i][j]=False
.
初始化:
先将
d[j][j]
全部初始化为False。然后令d[0][0]=True
(1)C++——思路1
class Solution {
public:
bool isMatch(string s, string p) {
int i = s.size()-1;
int j = p.size()-1;
return match(s,p,i,j);
}
bool match(string& s, string& p,int i ,int j){
if(i==-1){
while(j>=0){
if(p[j]=='*')
j=j-2;
else
return false;
}
return true;
}
if(j==-1){
if(i==-1)
return true;
else
return false;
}
if(p[j]=='.' || p[j]==s[i]){
return match(s,p,i-1,j-1);
}
else if(p[j]=='*'){
if(p[j-1]==s[i] || p[j-1]=='.')
return (match(s,p,i-1,j) || match(s,p,i,j-2));
else
return match(s,p,i,j-2);
}
else
return false;
}
};
(2)C+±dp
class Solution {
public:
bool isMatch(string s, string p) {
int m = s.size()+1;
int n = p.size()+1;
vector<vector<bool>> d(m,vector<bool>(n,false));
d[0][0]=true;
for(int j=1;j<n;j++){
if(p[j-1]=='*'){
d[0][j]=d[0][j-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]=='.')
d[i][j]=d[i-1][j-1];
if(p[j-1]=='*'){
if(p[j-2]==s[i-1] || p[j-2]=='.')
d[i][j]=(d[i-1][j])||(d[i][j-2]);
else
d[i][j]=d[i][j-2];
}
}
}
return d[m-1][n-1];
}
};
(3)python-dp
import numpy as np
class Solution:
def isMatch(self, s: str, p: str) -> bool:
m = len(s)+1
n = len(p)+1
d = np.zeros((m,n),dtype = np.int)
d[0][0]=1
for j in range (1,n,1):
if(p[j-1]=='*'):
d[0][j]=d[0][j-2]
for i in range(1,m,1):
for j in range(1,n,1):
if(p[j-1]==s[i-1] or p[j-1]=='.'):
d[i][j] = d[i-1][j-1]
if(p[j-1]=='*'):
if(p[j-2]==s[i-1] or p[j-2]=='.'):
d[i][j]=d[i][j-2] or d[i-1][j]
else:
d[i][j]=d[i][j-2]
return bool(d[m-1][n-1])
(4)python_1
import numpy as np
class Solution:
def isMatch(self, s: str, p: str) -> bool:
m = len(s)
n = len(p)
return self.match(s,p,m-1,n-1)
def match(self,s,p,i,j):
if i==-1:
while(j>-1):
if p[j]=='*':
j=j-2
else:
return False
return True
elif j==-1:
return False
else:
if p[j]==s[i] or p[j]=='.':
return self.match(s,p,i-1,j-1)
elif p[j]=='*':
if(p[j-1]==s[i] or p[j-1]=='.'):
return self.match(s,p,i-1,j) or self.match(s,p,i,j-2)
else:
return self.match(s,p,i,j-2)
else:
return False