Leetcode_正则表达式匹配

Leetcode_正则表达式匹配

题目

给你一个字符串s和一个字符规律p,请你来实现一个支持'.''*'的正则表达式匹配。

'.'匹配任意单个字符
'*'匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖整个字符串s的,而不是部分字符串。
 
 

动态规划方法

建立矩阵matrix记录匹配状态,matrix[i + 1][j + 1]表示字符规律p中前i个字符能否与s中的前j个字符相匹配。
这里将带'*'的字符和'*'视作一个整体,即在matrix中的状态行相同。

思路:从p中第一个匹配字符开始进行匹配,每一个匹配字符都与s中的所有(存在限制,后续说明)字符尝试匹配一次,并在matrix中进行记录。因此matrix的填写方式为:逐行从左至右填写。

注意
'*'的字符数量可以为0,所以存在多种匹配方式,譬如s"aaa"p"a*aaa"a*可以与第一个s中的第一个a进行匹配,但紧接着匹配第二个匹配字符(*后的a)时,需要退回到s中的第一个字符匹配,否则后面两个匹配字符无法完全匹配。
而不带'*'的匹配字符(在此称作独立匹配字符)的任何匹配都是硬匹配的,即后续匹配字符不能退回到独立匹配字符所匹配的字符之前进行匹配,譬如例子中第二个匹配字符与s中第一个a匹配后,第三个匹配字符就不能与该字符进行匹配。代码中将用变量mark标识目前硬匹配的最小索引。
 

代码:

bool isMatch(string s, string p) {
	bool matrix[256][256] = {0};      // 建立矩阵
    int flag;                         // 用于标记p中是否存在某个独立匹配字符没有得到匹配
    int mark = 0;                     // 标记硬匹配的最小索引
    for(int i = 0; i < p.length(); i++)  
        matrix[i][0] = 1;    // 矩阵左侧一列置1,便于后续判断是否进行匹配
    for(int i = 0; i < p.length() + 1; i++){
        flag = 1;    
        for(int j = mark; j < s.length() + 1; j++){
            if(p[i] == '*'){    // 匹配字符为*,直接将前一行的匹配情况抄下来
            	flag = 0;    // 非独立匹配字符,取消标记
                for(int k = 1; k < s.length() + 1; k++)
                    matrix[i + 1][k] = matrix[i][k];
            }
            else if(i < p.length() && p[i + 1] == '*'){    // 带*的匹配字符
                if(flag)
                    matrix[i + 1][j] = matrix[i][j];  // 解释1
                flag = 0;    // 非独立匹配字符,取消标记
                matrix[i + 1][j + 1] = matrix[i][j + 1];  // 解释2
                if(matrix[i][j] == 1 || matrix[i + 1][j] == 1){  // 解释3
                    if(p[i] == s[j] || p[i] == '.' || matrix[i][j + 1] == 1){
                        matrix[i + 1][j + 1] = 1;
                    }
                }
            }
            else if(matrix[i][j] == 1){  // 独立匹配字符的情况
                if(p[i] == s[j] || p[i] == '.'){
                    matrix[i + 1][j + 1] = 1;
                    if(flag)
                        mark = j + 1;
                    flag = 0;
                }
            }
        }
        if(flag){
            return 0;  // 独立匹配字符没有匹配项,匹配失败
        }
    }
    return matrix[p.length()][s.length()];  // 返回最终结果
}

解释1:在flag1时将前一行的匹配状态落到本行。因为带*的匹配字符的数目可以为0,这种情况下需要保留上一个匹配字符的匹配状态。

解释2:同样是为了保留上一个匹配字符的匹配状态,但分两部分进行是因为mark保留的是硬匹配匹配字符所对应的字符的下一个索引,因此解释1的部分是为了保留第一个匹配的状态。而后续的匹配状态由解释2对应的代码保留。可见,带*的匹配字符的状态为该字符的成功匹配情况和上一个匹配字符的匹配情况的并集。

解释3(动态规划的核心之一):带*的匹配字符能够进行匹配的两个条件。或是前一个匹配字符与前一个待匹配字符成功匹配,或是自己本身与前一个待匹配字符成功匹配。

解释4(动态规划的核心之二):独立匹配字符能够与当前带匹配字符进行匹配的条件,前一个匹配字符必须与前一个待匹配字符成功匹配。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值