Regular Expression Matching - LeetCode

Regular Expression Matching - LeetCode

题目
Implement regular expression matching with support for ‘.’ and ‘*’.
‘.’ Matches any single character.
‘*’ Matches zero or more of the preceding element.
The matching should cover the entire input string (not partial).
The function prototype should be:
bool isMatch(const char *s, const char *p)

Some examples:
isMatch(“aa”,”a”) → false
isMatch(“aa”,”aa”) → true
isMatch(“aaa”,”aa”) → false
isMatch(“aa”, “a*”) → true
isMatch(“aa”, “.*”) → true
isMatch(“ab”, “.*”) → true
isMatch(“aab”, “c*a*b”) → true


这道题要我们做一个正则表达式的匹配,正则表达式只包含字母、‘.’、‘*’。
函数声明bool isMatch(string s, string p)
其中s是待匹配字符串,p是正则表达式。

记录一下刚开始走过的坑:
最初有个很单纯的想法,从头到尾遍历一遍s,对于每个s中的字符,去检查一下p中下一个字符是否与之匹配,如果p的下一个字符是‘*’那么就要做一些特殊判断,总之分了挺多情况。
但是很遗憾这个方法行不通,,我碰到了下面这个例子:
s = “aaa”
p = “ab*a*c*a”
如果按照我刚才的方法,这里无法确定p中的a*到底对应s中几个a,也就是说当p的下一个字符为‘*’时,我不能确定该把这个‘*’当成‘a’来处理,还是结束这个‘*’去检查下一个字符。在这个例子中,如果把‘a*’中的‘*’当成‘a’来处理那就错了。
就算反过来,从尾部开始匹配也还是有这个问题。


正确的方法:
搜了一下正则表达式匹配算法,看到一篇博客,使用动态规划做的。不过这篇博客里的题目和我做的这道题还是有差别的,所以需要修改很多地方。
又搜了一下动态规划,简单的学了一下(大一就听说过这个高端的算法,,然而一直没有去学),再参考第一篇博客里的代码得出了这道题的答案。

其实主要的问题就是这个‘*’,不能确定它到底对应几个字符,这样就只能(应该是只能吧。。)用遍历的方法,遍历每一种可能,但如何遍历这个是难点。
这里用了一个二维bool数组m[128][128],m[i][j]记录s的长度为i的前缀与p的长度为j的前缀是否匹配,如果匹配m[i][j]就为true。
这样就可以开始遍历了,首先m[0][0]是显然为true的,
然后对i=1,j=1,2,…,p.length,分别求出m[i][j]
再对i=2,j=1,2,…,p.length,分别求出m[i][j]
直到i=s.length,j=1,2,…,p.length。
递推式为:

if (p[j] == '*') {
    // 检查到一个'*'后,'*'前面的那个字符是可以忽略的,所以要修改一下某些匹配关系
    if (!m[i][j+1]) m[i][j+1] = m[i][j-1];
    m[i+1][j+1] = m[i+1][j-1] || m[i+1][j] || (m[i][j+1] && (p[j-1] == s[i] || p[j-1] == '.'));
} else {
    m[i+1][j+1] = m[i][j]&&(p[j] == s[i] || p[j] == '.');
}

完整代码:

#include <iostream>
#include <cstdlib>
using namespace std;

class Solution {
public:
    bool isMatch(string s, string p) {

        if (p.length() == 0 && s.length() != 0) return false;
        if (p == ".*") return true;

        bool  m[128][128] = {0};
        m[0][0] = true;
        int i = 0, j = 0;
        int sum = 0;
        for (j = 0; j < p.length(); j++) {
            if (p[j] != '*') sum++;
            else sum--;
            if (sum == 0) m[0][j+1] = true;
        }

        for (i = 0; i < s.length(); i++) {
            for (j = 0; j < p.length(); j++) {
                if (p[j] == '*') {
                    if (!m[i][j+1]) m[i][j+1] = m[i][j-1];
                    m[i+1][j+1] = m[i+1][j-1] || m[i+1][j] || (m[i][j+1] && (p[j-1] == s[i] || p[j-1] == '.'));
                } else {
                    m[i+1][j+1] = m[i][j]&&(p[j] == s[i] || p[j] == '.');
                }
            }
        }
        return m[s.length()][p.length()];
    }
};

做这道题跨时7个小时,虽然7个小时里不是一直在做这题。看了下最快的方法也是用动态规划做的,思路应该大同小异所以就没有细看。。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值