题目描述
请实现一个函数用来匹配包括’.‘和’‘的正则表达式。模式中的字符’.‘表示任意一个字符,而’'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"abaca"匹配,但是与"aa.a"和"ab*a"均不匹配。
测试用例
- 功能测试(模式字符串里包含普通字符、‘.’、‘’;模式字符串和输入字符串匹配/不匹配;“.”这个组合真的是吃屎)
- 特殊输入测试(输入字符串和模式字符是null、空字符串)
题目考点
- 考察应聘者对字符串的编程能力
- 考察应聘者对正则表达式的理解
- 考察应聘者思维的全面性。在应聘者写完代码之后,面试官会要求他测试自己的代码,这个时候应聘者要充分考虑普通字符、‘.’、‘*’三者的排列组合,尽量完备地想出所有可能的测试用例。
因此,本题的状态共有 m × n m \times n m×n 种,应定义状态矩阵 dp , d p [ i ] [ j ] dp[i][j] dp[i][j]代表 s [ : i ] s[:i] s[:i] 与 p [ : j ] p[:j] p[:j]是否可以匹配。
做好状态定义,接下来就是根据 「普通字符」 , 「.」 , 「*」三种字符的功能定义,分析出动态规划的转移方程。
复杂度分析:
- 时间复杂度 O ( M N ) O(MN) O(MN) : 其中 M, NM,N 分别为 s 和 p 的长度,状态转移需遍历整个 dp 矩阵;
- 空间复杂度 O ( M N ) O(MN) O(MN) : 状态矩阵 dp 使用 O ( M N ) O(MN) O(MN) 的额外空间。
代码
class Solution {
public boolean isMatch(String s, String p) {
int m = s.length() + 1, n = p.length() + 1;
boolean[][] dp = new boolean[m][n];
dp[0][0] = true;
for(int j = 2; j < n; j += 2)
dp[0][j] = dp[0][j - 2] && p.charAt(j - 1) == '*';
for(int i = 1; i < m; i++) {
for(int j = 1; j < n; j++) {
dp[i][j] = p.charAt(j - 1) == '*' ?
dp[i][j - 2] || dp[i][j - 1] || dp[i - 1][j] && (s.charAt(i - 1) == p.charAt(j - 2) || p.charAt(j - 2) == '.') :
dp[i - 1][j - 1] && (p.charAt(j - 1) == '.' || s.charAt(i - 1) == p.charAt(j - 1))
}
}
return dp[m - 1][n - 1];
}
}