题目描述:
给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 ‘.’ 和 ‘*’ 的正则表达式匹配。
‘.’ 匹配任意单个字符
‘*’ 匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。
说明:
s 可能为空,且只包含从 a-z 的小写字母。
p 可能为空,且只包含从 a-z 的小写字母,以及字符 . 和 *。
示例 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
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/regular-expression-matching
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路:
还算是比较典型的动态规划问题,主要问题是在动态转移方程,这个稍后再说。
首先创建一个二维数组,cek[si][pi] ,其中脚标是指在其对应的字符串中的位置。
由于存在空字符串,所以创建的二维数组应该多一位,即0位置代表的是空字符串。
现在需要考虑的就是动态转移方程了,
- 首先是最简单的既不为‘ * ’也不为‘.’的情况,那就是if(s.charAt(si) == p.charAt(pi)) cek[si+1][pi+1] = cek[si][pi]
- 同样的当p的位置为’.'的情况,和上边相同 ,if(p.charAt(pi) == ‘.’) cek[si+1][pi+1] = cek[si][pi] 。1和2可以综合成一个
- 比较复杂的当p的位置为’* ’的情况,先说一下方程 if(p,charAt(pi) == ‘* ‘) cek[si+1][pi+1] = (cek[si+1][pi-1]) || (cek[si][pi+1]&&(s.charAt(si) == p.charAt(pi-1)||p.charAt(pi-1)==’.’));
可以看出这种情况是由两部分组成:
①示例:s为“aa”,p为“aab* ”,当si为1,pi都为,3的时候,因为b* 可以认为是空的,所以这种情况cek[si][pi] = cek[si][pi-1]。cek[2][2] 为true,所以当前也为true。
②示例:s为“aa”,p为“a*”,si与pi都为1,因为a* 可认为有若干个a,所以判断[a]与[a*]可以匹配后,只要s串中的第二个a,和p串中的*前边的字母能够匹配就行了。即cek[si][pi+1]&&(s.charAt(si) ==p.charAt(pi-1)||p.charAt(pi-1) ==’.’)
反思错误:
①忘记对s串为空时候进行初始化了。因为s为空的时候,p可以为{空、a* 、.* 等等},所以cek[0][?] 需要初始化。
②读题不完整,没有意识到“ab”与“.* ”居然可以匹配,也是啊,“ab”和“…”是可以匹配上。
Java代码:
class Solution {
public boolean isMatch(String s, String p) {
int slen = s.length();
int plen = p.length();
boolean[][] cek = new boolean[slen+1][plen+1];
//s为空串时的初始化
cek[0][0] = true;
for(int pi=0;pi<plen;++pi){
if(p.charAt(pi)=='*') cek[0][pi+1] = cek[0][pi-1];
}
for(int si=0;si<slen;++si){
for(int pi=0;pi<plen;++pi){
if(p.charAt(pi) == '*') {
cek[si+1][pi+1] = (cek[si+1][pi-1]) ||
(cek[si][pi+1]&&(s.charAt(si)==p.charAt(pi-1)||p.charAt(pi-1)=='.'));
}
else if(s.charAt(si)==p.charAt(pi) || p.charAt(pi)=='.') cek[si+1][pi+1] = cek[si][pi];
}
}
return cek[slen][plen];
}
}
执行结果:
通过
显示详情
执行用时 :3 ms, 在所有 java 提交中击败96.64% 的用户
内存消耗 :36.2 MB, 在所有 java 提交中击败了87.82% 的用户