梳理思路,使用Java和Python分别解决动态规划类问题。
题目描述
给你一个字符串 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 解释:".*" 表示可匹配零个或多个('*')任意字符('.')。
解题思路
这个问题可以通过使用动态规划(Dynamic Programming, DP)来解决。动态规划是一种通过把原问题分解为相对简单的子问题的方式来求解复杂问题的方法。
我们可以创建一个布尔类型的 DP 表格 dp[i][j]
,其中 dp[i][j]
表示字符串 s
的前 i
个字符与模式 p
的前 j
个字符是否能够匹配。
动态规划方程如下:
- 当
p[j - 1] == s[i - 1]
或p[j - 1] == '.'
时,dp[i][j] = dp[i - 1][j - 1]
。 - 当
p[j - 1] == '*'
时,我们需要考虑两种情况:- 如果
p
的前一个字符不匹配s
的当前字符,则dp[i][j] = dp[i][j - 2]
,这表示我们将a*
作为空字符串。 - 如果
p
的前一个字符匹配s
的当前字符或者p
的前一个字符是.
,则dp[i][j] = dp[i - 1][j]
。
- 如果
初始化条件如下:
dp[0][0] = true
,因为两个空字符串是可以匹配的。- 对于
dp[i][0]
,其中i > 0
,始终为false
,因为空模式不能匹配非空字符串。 - 对于
dp[0][j]
,其中j > 0
,如果p[j - 1] == '*'
,则dp[0][j] = dp[0][j - 2]
。
完整代码
java
public class Solution {
public boolean isMatch(String s, String p) {
if (s == null || p == null) {
return false;
}
boolean[][] dp = new boolean[s.length() + 1][p.length() + 1];
dp[0][0] = true;
for (int i = 0; i <= s.length(); i++) {
for (int j = 1; j <= p.length(); j++) {
if (p.charAt(j - 1) == '*') {
dp[i][j] = dp[i][j - 2];
if (i > 0 && (p.charAt(j - 2) == '.' || p.charAt(j - 2) == s.charAt(i - 1))) {
dp[i][j] = dp[i][j] || dp[i - 1][j];
}
} else {
if (i > 0 && (p.charAt(j - 1) == '.' || p.charAt(j - 1) == s.charAt(i - 1))) {
dp[i][j] = dp[i - 1][j - 1];
}
}
}
}
return dp[s.length()][p.length()];
}
}
通过
python
class Solution:
def isMatch(self, s: str, p: str) -> bool:
dp = [[False] * (len(p) + 1) for _ in range(len(s) + 1)]
dp[0][0] = True # 两个空字符串是匹配的
# 初始化dp[0][j],处理模式p的前j个字符与空字符串s的匹配情况
for j in range(1, len(p) + 1):
if p[j - 1] == '*':
dp[0][j] = dp[0][j - 2]
# 填充dp表格
for i in range(1, len(s) + 1):
for j in range(1, len(p) + 1):
if p[j - 1] == '*':
# '*'代表前一个字符出现0次或多次
dp[i][j] = dp[i][j - 2] or (dp[i - 1][j] and (s[i - 1] == p[j - 2] or p[j - 2] == '.'))
else:
# 当前字符直接匹配或'.'匹配任意单个字符
dp[i][j] = dp[i - 1][j - 1] and (s[i - 1] == p[j - 1] or p[j - 1] == '.')
return dp[-1][-1] # 返回整个字符串s和模式p的匹配结果
通过