题目描述
给你一个字符串 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
解释:".*" 表示可匹配零个或多个('*')任意字符('.')。
提示:
- 1 <= s.length <= 20
- 1 <= p.length <= 30
- s 只包含从 a-z 的小写字母。
- p 只包含从 a-z 的小写字母,以及字符 . 和 *。
- 保证每次出现字符 * 时,前面都匹配到有效的字符
个人解法
Java(递归)
public static boolean isMatch(String s, String p) {
int pl=p.length(),sl=s.length();
//如果p长为0,s不为0肯定无法匹配(s=“a”,p=“”)
if (pl == 0) {
return sl == 0;
}
//存储判断第一个字符是否可能相等的结果
//①s="a",p="a" ②s="a",p="." 这两种情况都相等
boolean result = (sl != 0 && (s.charAt(0) == p.charAt(0) || p.charAt(0) == '.'));
if (pl>=2&&p.charAt(1)=='*') {
//s="aaabc",p="a*abc"
//左=>新s="aaabc",新p="abc“假设a*代表0个字符
//右=>新s="aabc",新p="a*abc"假设从s中取出一个a(可能和p中不一样,那就是false)消掉
return isMatch(s,p.substring(2))||(result&&isMatch(s.substring(1),p));
}else {
//s[0]=p[0]&&sl=1&&pl=1 s="a",p="a"
//s[0]=p[0]&&p[1]!="*" s="ab",p="ab*"相当于判断s="b",p="b*"
//s[0]!=p[0]&&p[1]!="*" s="ab",p="bb*" 结果为false
return result&&isMatch(s.substring(1),p.substring(1));
}
}
JavaScript
/**
* @param {string} s
* @param {string} p
* @return {boolean}
*/
var isMatch = function (s, p) {
if (p.length === 0) {
return s.length === 0;
}
const result = s.length !== 0 && (s[0] === p[0] || p[0] === '.');
if (p.length >= 2 && p[1] === '*') {
return isMatch(s, p.substring(2)) || (result && isMatch(s.substring(1), p));
} else {
return result && isMatch(s.substring(1), p.substring(1));
}
};
更优解法
Java(动态规划)
消掉一个a的情况可分解为消掉多个a的第一步以及剩下去消掉0个
class Solution {
public boolean isMatch(String s, String p) {
int m = s.length();
int n = p.length();
boolean[][] f = new boolean[m + 1][n + 1];
f[0][0] = true;
for (int i = 0; i <= m; ++i) {
for (int j = 1; j <= n; ++j) {
//如果p(j-1)等于"*"
if (p.charAt(j - 1) == '*') {
//s消掉0个相同字符
f[i][j] = f[i][j - 2];
//s消掉一个相同字符或其他情况
if (matches(s, p, i, j - 1)) {
f[i][j] = f[i][j] || f[i - 1][j];
}
} else {
//如果p(j-1)≠"*"
if (matches(s, p, i, j)) {
f[i][j] = f[i - 1][j - 1];
}
}
}
}
return f[m][n];
}
public boolean matches(String s, String p, int i, int j) {
if (i == 0) {
return false;
}
if (p.charAt(j - 1) == '.') {
return true;
}
return s.charAt(i - 1) == p.charAt(j - 1);
}
}
JavaScript
let isMatch = function (s, p) {
let dp = Array(s.length + 1);
for (let i = 0; i < dp.length; i++) {
dp[i] = Array(p.length + 1).fill(false)
}
dp[0][0] = true;
for (let i = 1; i < p.length; i++) {
if (p.charAt(i) === "*") {
dp[0][i + 1] = dp[0][i - 1]
}
}
for (let i = 0; i < s.length; i++) {
for (let j = 0; j < p.length; j++) {
if (p.charAt(j) === '.') {
dp[i + 1][j + 1] = dp[i][j]
}
if (p.charAt(j) === s.charAt(i)) {
dp[i + 1][j + 1] = dp[i][j]
}
if (p.charAt(j) === '*') {
if (p.charAt(j - 1) !== s.charAt(i) && p.charAt(j - 1) !== '.') {
dp[i + 1][j + 1] = dp[i + 1][j - 1]
} else {
dp[i + 1][j + 1] = (dp[i + 1][j] || dp[i][j + 1] || dp[i + 1][j - 1])
}
}
}
}
return dp[s.length][p.length]
};