[LeetCode][H0010]正则表达式匹配(Java)(动态规划)

题目描述:

给你一个字符串 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位置代表的是空字符串。
现在需要考虑的就是动态转移方程了,

  1. 首先是最简单的既不为‘ * ’也不为‘.’的情况,那就是if(s.charAt(si) == p.charAt(pi)) cek[si+1][pi+1] = cek[si][pi]
  2. 同样的当p的位置为’.'的情况,和上边相同 ,if(p.charAt(pi) == ‘.’) cek[si+1][pi+1] = cek[si][pi] 。1和2可以综合成一个
  3. 比较复杂的当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% 的用户

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值