题目地址:
给定一个字符串
s
s
s和一个模式串
p
p
p,
p
p
p中含字母,'.'
或者'*'
。其中'.'
可以匹配任何单个字符,'*'
可以匹配其之前的字符重复
0
0
0次或大于等于
1
1
1次。问
s
s
s是否符合
p
p
p所代表的模式。
思路是动态规划。设
f
[
i
]
[
j
]
f[i][j]
f[i][j]是
s
s
s的前
i
i
i个字符是否能匹配模式串
p
p
p里的前
j
j
j个字符(
i
i
i和
j
j
j都是从
1
1
1开始计数)。我们可以按照
p
[
j
−
1
]
p[j-1]
p[j−1]是如何与
s
s
s匹配的来分类:
1、若
p
[
j
−
1
]
p[j-1]
p[j−1]是字母或者是'.'
,那么
p
[
j
−
1
]
p[j-1]
p[j−1]要必然与
s
[
i
−
1
]
s[i-1]
s[i−1]进行匹配,并且要求
p
[
0
:
j
−
2
]
p[0:j-2]
p[0:j−2]与
s
[
0
:
i
−
2
]
s[0:i-2]
s[0:i−2]要匹配。此时
f
[
i
]
[
j
]
=
(
p
[
j
−
1
]
=
.
∨
p
[
j
−
1
]
=
s
[
i
−
1
]
)
∧
f
[
i
−
1
]
[
j
−
1
]
f[i][j]=(p[j-1]=.\lor p[j-1]=s[i-1])\land f[i-1][j-1]
f[i][j]=(p[j−1]=.∨p[j−1]=s[i−1])∧f[i−1][j−1]2、若
p
[
j
−
1
]
p[j-1]
p[j−1]是'*'
,那么这个'*'
连同其前一个字符应该看成一个整体:
如果这个整体按照出现
0
0
0次来匹配,那么结果就是
f
[
i
]
[
j
−
2
]
f[i][j-2]
f[i][j−2](此时需要保证
j
≥
2
j\ge 2
j≥2,事实上如果
p
p
p是个合法的模式串,应该有如果
p
[
j
−
1
]
p[j-1]
p[j−1]是'*'
那么
j
≥
2
j\ge 2
j≥2。但如果
p
p
p不合法,我们也应该返回false。所以这里还是需要额外判断一下
j
≥
2
j\ge 2
j≥2,只是为了将不合法的情形包含进去);
如果这个整体按照出现大于等于
1
1
1次来匹配,那么就要求或者
p
[
j
−
2
]
p[j-2]
p[j−2]是'.'
,或者
s
[
i
−
1
]
=
p
[
j
−
2
]
s[i-1]=p[j-2]
s[i−1]=p[j−2],这个整体匹配完之后,还需要
s
[
0
:
i
−
2
]
s[0:i-2]
s[0:i−2]与
p
[
0
:
j
−
1
]
p[0:j-1]
p[0:j−1]匹配,也就是还要求
f
[
i
−
1
]
[
j
]
f[i-1][j]
f[i−1][j]为true。注意,这里是
p
[
0
:
j
−
1
]
p[0:j-1]
p[0:j−1],因为那个整体是匹配大于等于
1
1
1次的出现,将
s
s
s末字符匹配完之后,前面有可能还有
s
[
i
−
1
]
s[i-1]
s[i−1]出现,也就是那个整体匹配的一部分是
s
[
i
−
1
]
s[i-1]
s[i−1]而不是全部。
综上,此时:
f
[
i
]
[
j
]
=
f
[
i
]
[
j
−
2
]
∨
(
(
p
[
j
−
2
]
=
.
∨
p
[
j
−
2
]
=
s
[
i
−
1
]
)
∧
f
[
i
−
1
]
[
j
]
)
f[i][j]=f[i][j-2]\lor ((p[j-2]=. \lor p[j-2]=s[i-1])\land f[i-1][j])
f[i][j]=f[i][j−2]∨((p[j−2]=.∨p[j−2]=s[i−1])∧f[i−1][j])考虑初始条件,空字符串可以和空模式匹配,而非空字符串无法和空模式匹配,所以
f
[
0
]
[
0
]
f[0][0]
f[0][0]是true,而当
i
>
0
i>0
i>0时,
f
[
i
]
[
0
]
f[i][0]
f[i][0]是false。但是
f
[
0
]
[
j
]
f[0][j]
f[0][j]一下子是看不出来的,需要在递推的过程中算出来。代码如下:
class Solution {
public:
bool isMatch(string s, string p) {
int n = s.size(), m = p.size();
s = " " + s;
p = " " + p;
bool f[n + 1][m + 1];
memset(f, 0, sizeof f);
f[0][0] = true;
// 到此,f[.][0]就已经全算出了,接下来只需要求f[.>0][j]
for (int j = 1; j <= m; j++)
for (int i = 0; i <= n; i++)
if (p[j] != '*')
f[i][j] = i && (p[j] == '.' || s[i] == p[j]) && f[i - 1][j - 1];
else
f[i][j] = j >= 2 && f[i][j - 2] ||
i && f[i - 1][j] && (p[j - 1] == '.' || s[i] == p[j - 1]);
return f[n][m];
}
};
时空复杂度 O ( l s l p ) O(l_sl_p) O(lslp)。