正则表达式是一种强大的字符串匹配工具,允许我们根据某种模式来查找、验证和提取字符串。在本文中,我们将探讨如何使用 Java 来实现支持 ‘.’ 和 ‘*’ 的正则表达式匹配,其中:
这个问题的关键在于理解 ‘*’ 的含义以及如何构建匹配规则。我们将使用动态规划来解决这个问题。
动态规划是解决此类字符串匹配问题的一种强大方法。我们可以使用一个二维布尔数组 dp,其中 dp[i][j] 表示字符串 s 的前 i 个字符和模式 p 的前 j 个字符是否匹配。接下来,让我们逐步构建解决方案。
首先,我们需要初始化 dp 数组。考虑以下情况:
dp[0][0] 表示空字符串和空模式,它们是匹配的,所以 dp[0][0] = true。dp[i][0] 表示非空字符串与空模式,它们永远不会匹配,所以 dp[i][0] = false。dp[0][j] 表示空字符串与非空模式,此时我们需要考虑 * 号的情况,如果 p[j-1] 是 *,则可以消除前一个字符,即 dp[0][j] = dp[0][j-2]。接下来,我们需要考虑 dp[i][j] 的状态转移。我们可以根据 s[i-1] 和 p[j-1] 来决定 dp[i][j] 的值。
s[i-1] 和 p[j-1] 匹配(或 p[j-1] 是 .),则 dp[i][j] 取决于 dp[i-1][j-1],即 dp[i][j] = dp[i-1][j-1]。p[j-1] 是 *,则需要考虑 * 号的两种用法:
* 匹配零次前面的字符,即 dp[i][j] = dp[i][j-2]。* 匹配一次或多次前面的字符,即 s[i-1] 和 p[j-2] 匹配,并且 dp[i][j] 取决于 dp[i-1][j],即 dp[i][j] = dp[i-1][j]。根据上述思路,我们可以实现如下的 Java 代码:
class Solution {
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 (s.charAt(i - 1) == p.charAt(j - 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];
}
}
现在让我们来测试一些示例来验证我们的实现是否正确。
输入:s = “aa”, p = “a”
输出:false
这是一个简单的示例,因为模式 p 中的字符和字符串 s 中的字符无法匹配。所以返回 false。
输入:s = “aa”, p = “a*”
输出:true
在这个示例中,由于 * 可以匹配零个或多个前面的字符,字符串 “aa” 可以被视为 ‘a’ 重复了一次。所以返回 true。
输入:s = “ab”, p = “.*”
输出:true
模式 “.*” 可以匹配零个或多个任意字符,所以它可以匹配字符串 “ab”。返回 true。
正则表达式匹配是一个有趣且复杂的问题,但通过使用动态规划,我们可以有效地解决它。我们在上面提供的 Java 代码中演示了如何实现支持 ‘.’ 和 ‘*’ 的正则表达式匹配。希望本文对你理解和解决这个问题有所帮助。如果你有任何问题或疑问,请随时提出。