1、题目
请实现一个函数用来匹配包含'. '和'*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(含0次)。在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"ab*ac*a"匹配,但与"aa.a"和"ab*a"均不匹配。
示例 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
s 可能为空,且只包含从 a-z 的小写字母。
p 可能为空,且只包含从 a-z 的小写字母以及字符 . 和 *,无连续的 '*'。
题目来源:https://leetcode-cn.com/problems/zheng-ze-biao-da-shi-pi-pei-lcof
2、思路
我们先假设两个字符串的长度,设:
s.length() = n
p.length() = m;
再设s的字符下标为i,p的字符下标为j,我们用 f [s : i, p : j] 来表示当s字符串以下标为 i 的字
符为结尾时,和p字符串以下标为 j 的字符为结尾时,二者所代表的字符串是否等价,是一个
布尔值
根据题目要求,最终需要得到的结果是:当i = n - 1, j = m - 1时, f [s : i, p : j]能够匹配,
而f [s : i, p : j]的状态(是否匹配)是可以从前面的状态转移而来的
我们将 f [s : i, p : j] 表示成一个boolean类型的二维数组
boolean[][] dp = new boolean[n + 1][m + 1]
dp[0][0]表示当两个字符串都为空串时能否匹配,根据题意可知 dp[0][0] = true
dp[i][j]表示f [s : i - 1, p : j - 1]的状态,true为匹配,false为不匹配
判断dp[i][j]的条件如下:
当p字符串以下标为j - 1的字符为结尾时,若该字符为 '*',有以下规律
1、当 * 的作用是使下标为 j - 2的字符重复0次时
这可以看成是将下标为 j - 2的字符消除,这时只需要判断以下标为 j - 3 为结尾的字
符串与以下标为 i - 1为结尾的能否匹配,即dp[i][j - 2]的状态
也即:当dp[i][j - 2] = true时, dp[]i[j] = true
2、当 * 的作用是使下标为 j - 2 的字符重复时
首先自然是要先判断 * 之前的字符也即下标为j - 2下标与为 i - 1的字符是否等价,等
价的情况有两种,第一种是 * 之前的字符与下标为 i - 1的字符相同,第二种是 * 之
前的字符为 . ,若此步判断结果为true,则进行以下判断,反之:dp[i][j] = false
判断dp[i - 1][j]的状态是否为true,原因如下:
(1)若dp[i - 1][j] = true时,* 在上一个字符的匹配时起的是消除作用,可看例子:
s字符串:aa
p字符串:aab*
此时消除掉b字符刚好能够使得二者匹配,此时加入下标为 i - 1的字符:b
就变成了:
s字符串:aab
p字符串:aab*
依旧可以匹配,此时 * 的作用由消除 b 转变成了使 b 重复一次
(2)dp[i][j] = true时, * 在上一个字符匹配时起的是重复作用,有例子如下:
s字符串:aaaa
p字符串:aaa*
此时加入下标为 i - 1的字符:a
s字符串:aaaaa
p字符串:aaa*
依旧可以匹配,此时 * 的作用是由重复一次变成了重复两次
当p字符串以下标为j - 1的字符为结尾时,若该字符不为 '*',则
判断该字符与下标为 i - 1的字符是否等价,等价的条件为相同或该字符为 .,若等价则
进行后续判断,反之则:dp[i][j] = false
接着判断以下标为i - 1为结尾的字符串和以下标为 j - 2的字符为结尾的字符串是否匹配
也即:dp[i - 1][j - 1]的状态即可,若为true则dp[i][j] = true,反之则dp[i][j] = false
3、编码
class Solution {
public boolean isMatch(String s, String p) {
char[] ss = s.toCharArray();
char[] ps = p.toCharArray();
int n = ss.length + 1, m = ps.length + 1;
boolean[][] dp = new boolean[n][m];
dp[0][0] = true;
//判断s为空串时能否匹配
for(int j = 2; j < m; j += 2) {
dp[0][j] = dp[0][j - 2] && ps[j - 1] == '*';
}
for(int i = 1; i < n; i++) {
for(int j = 1; j < m; j++) {
if(ps[j - 1] == '*') {
if(j >= 2) {
dp[i][j] = dp[i][j - 2];
}
dp[i][j] = dp[i][j] || (ss[i - 1] == ps[j - 2] || ps[j - 2] == '.') && dp[i - 1][j];
}else {
dp[i][j] = (ss[i - 1] == ps[j - 1] || ps[j - 1] == '.') && dp[i - 1][j - 1];
}
}
}
return dp[n - 1][m - 1];
}
}