题目描述
给你一个字符串 s
和一个字符规律 p
,请你来实现一个支持 '.'
和 '*'
的正则表达式的匹配。
‘.’ 匹配任意单个字符
‘*’ 匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖整个输入字符串(s
),而不是部分字符串。
说明:
's'
可能为空,且只包含从 a-z
的小写字母。
'p'
可能为空,且只包含从 a-z
的小写字母,以及字符 .
, *
。
实现思路
我们可以使用动态规划来解决这个问题。定义一个二维数组 dp
,其中 dp[i][j]
表示 s
的前 i
个字符是否能够与 p
的前 j
个字符匹配。初始化 dp[0][0] = true
,表示空字符串与空模式匹配。对于 p
中每一个位置 j
,如果 p[j-1]
是 *
,那么 dp[0][j]
的值取决于 p[j-2]
是否可以匹配 s
的空串。
对于非边界情况,我们有:
- 如果
p[j-1] != '*'
,那么dp[i][j]
的值取决于s[i-1]
是否能与p[j-1]
匹配,并且dp[i-1][j-1]
是否为true
。 - 如果
p[j-1] == '*'
,那么dp[i][j]
的值取决于p[j-2]
是否能与s[i-1]
匹配,并且dp[i][j-2]
是否为true
,或者dp[i][j-1]
是否为true
。
算法实现
C
#include <stdbool.h>
#include <string.h>
bool isMatch(char *s, char *p) {
int m = strlen(s);
int n = strlen(p);
bool dp[m + 1][n + 1];
memset(dp, false, sizeof(dp));
dp[0][0] = true;
for (int j = 1; j <= n; ++j) {
if (p[j - 1] == '*') {
dp[0][j] = dp[0][j - 2];
}
}
for (int i = 1; i <= m; ++i) {
for (int j = 1; j <= n; ++j) {
if (p[j - 1] == '.' || s[i - 1] == p[j - 1]) {
dp[i][j] = dp[i - 1][j - 1];
} else if (p[j - 1] == '*') {
dp[i][j] = dp[i][j - 2] || ((s[i - 1] == p[j - 2] || p[j - 2] == '.') && dp[i - 1][j]);
}
}
}
return dp[m][n];
}
Python
def isMatch(s: str, p: str) -> bool:
m, n = len(s), len(p)
dp = [[False] * (n + 1) for _ in range(m + 1)]
dp[0][0] = True
for j in range(1, n + 1):
if p[j - 1] == '*':
dp[0][j] = dp[0][j - 2]
for i in range(1, m + 1):
for j in range(1, n + 1):
if p[j - 1] == '.' or s[i - 1] == p[j - 1]:
dp[i][j] = dp[i - 1][j - 1]
elif p[j - 1] == '*':
dp[i][j] = dp[i][j - 2] or ((s[i - 1] == p[j - 2] or p[j - 2] == '.') and dp[i - 1][j])
return dp[m][n]
Java
public boolean isMatch(String s, String p) {
int m = s.length();
int n = p.length();
boolean[][] dp = new boolean[m + 1][n + 1];
dp[0][0] = true;
for (int j = 1; j <= n; ++j) {
if (p.charAt(j - 1) == '*') {
dp[0][j] = dp[0][j - 2];
}
}
for (int i = 1; i <= m; ++i) {
for (int j = 1; j <= n; ++j) {
if (p.charAt(j - 1) == '.' || s.charAt(i - 1) == p.charAt(j - 1)) {
dp[i][j] = dp[i - 1][j - 1];
} else if (p.charAt(j - 1) == '*') {
dp[i][j] = dp[i][j - 2] || ((s.charAt(i - 1) == p.charAt(j - 2) || p.charAt(j - 2) == '.') && dp[i - 1][j]);
}
}
}
return dp[m][n];
}
时间复杂度
时间复杂度为 O(mn),其中 m 是 s
的长度,n 是 p
的长度。空间复杂度也为 O(mn)。