剑指 Offer 19. 正则表达式匹配

目录

一、题目

二、分析

一、确定状态转移关系:

二、选择初始值:

三、代码

四、总结


一、题目

        请实现一个函数用来匹配包含'. ''*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(含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" 可
示例 3:
输入:
s = "ab"
p = ".*"
输出: true
解释: ".*" 表示可匹配零个或多个('*')任意字符('.')。

  • s 可能为空,且只包含从 a-z 的小写字母。
  • p 可能为空,且只包含从 a-z 的小写字母以及字符 . 和 *,无连续的 '*'

二、分析

定义dp[i][j]表示字字符串s的前i个字符和p的前j个字符是否匹配。false/ture

dp[i][j]是flase还是ture<==>s[i] vs p[j]<==>s[i-1] vs p[j-1];

 

        字符串p[j]可能是: a~z的普通字符、"."、"*" 三种字符,分别进行分析。

一、确定状态转移关系:

1、p[j]=普通字符:

                                        1.1、s[i]=p[j]:dp[i][j]=dp[i-1][j-1];

                                         1.2、 s[i]!=p[j]:  dp[i][j]=flase;

2、p[j]=".",此时p[j]是万能符 :dp[i][j]=dp[i-1][j-1];

3、p[j]="*",因为"*"表示p的第j个字符等于第j-1个字符,所以需要考虑p[j-1]是什么字符:

                 (1)p[j-1] !=s[i]:相当于把p[j]剔除 dp[i][j]=dp[i][j-2];

                  (2)p[j-1]=s[i]:此时根据"*"可匹配的字符个数进行讨论

                                     2.1、"*"匹配0个:dp[i][j]=dp[i][j-2];

                                     2.2、"*"匹配1个:相当于删除p的第j自身进行比较==>dp[i][j]=dp[i][j-1];

                                     2.3、"*"匹配n个:相当于删除s的第i个进行比较==>dp[i][j]=dp[i-1][j];

二、选择初始值:

为了让dp[i][j]不越界

遍历时是从i开始遍历,递减:所以需要枚举dp[0][j]可能出现的情况:

                               dp[0][0]=true;

                               dp[0][1]=false;

                                dp[0][j]:j>1需要考虑第二个字符是否为"*";

                                           p[j]=*,相当于要删除两个:dp[0][j]=dp[0][j-2];

                                           p[j]!="*":dp[0][j]=flase;

                                                                                                        

                                                                

三、代码

class Solution {
    public boolean isMatch(String s, String p) {
//        边界约束
        if(s==null||p==null){
                return true;
        }
        int n = s.length();
        int m = p.length();
        boolean[][] dp= new boolean[n+1][m+1];

//        把可能为true的情况找出来
        dp[0][0] = true;
        for (int j = 2; j <= m; j++) {
            if(p.charAt(j-1)=='*'){
//                相当于消除前面两个
                dp[0][j] = dp[0][j-2];

            }
        }

        for (int i = 1; i <= n ; i++) {
            for (int j = 1; j <= m; j++) {

//           j不为*
                if(p.charAt(j-1)!='*'){
                    if(p.charAt(j-1)=='.'||p.charAt(j-1) == s.charAt(i-1)){
                        dp[i][j]=dp[i-1][j-1];
                    }

                }else {
//                    第j-1个字符不匹配
                    if(p.charAt(j-2)!=s.charAt(i-1)&&p.charAt(j-2)!='.'){
                        dp[i][j] = dp[i][j-2];
                    }else {
//                        匹配0/1/n
                        dp[i][j] = dp[i][j-2]||dp[i][j-1]||dp[i-1][j];
                    }
                }
            }

        }

        return dp[n][m];

    }
}

运行结果:

四、总结

        

        动态规划核心是使用数组对历史记录进行保存从而避免重复的计算、

可分为三步进行处理:

                                1、对dp[i][j]的定义。

                                2、分析确定状态转移方程。

                                3、确定dp[0][0]的初始值。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值