LeetCode算法练习之正则表达式匹配

32 篇文章 0 订阅

说实话,这个题目确实是到目前为止练习的最难的一道题目,但是也是意义非常重大的一道题目,它点明了动态规划的原理。

首先,我们仔细审题,先进行第一步思考,a*表实可以有0个a,也可以有任意个a,这样就可以把p转换成多个字符串,只要s和其中一个相等,就可以匹配。

再深入想想,其实正则表达式匹配是一个“策略”的问题。比如s="aaa",p="a*a",时,就有各种匹配方式。其中有的可以匹配,有的不能匹配。只要有一种方式匹配,就说明可以。每次遇到a*时,我们都要做出选择,选择匹配0,1,2等等。想一下我们对比字符串的方式,就可以想出避免无限循环的方法——匹配时不是从p中增加若干个a来匹配s,而是从s中去掉若干个a,如果没法去a则循环终止。

编写程序的时候,由于题目有“选择”成分,想到图的搜索(其实就是暴力走迷宫),我们就可以采用递归的方式。(用的官方题解,自己的程序有点问题)

class Solution {
    public boolean isMatch(String text, String pattern) {
        if (pattern.isEmpty()) return text.isEmpty();
        boolean first_match = (!text.isEmpty() &&
                               (pattern.charAt(0) == text.charAt(0) || pattern.charAt(0) == '.'));

        if (pattern.length() >= 2 && pattern.charAt(1) == '*'){
            return (isMatch(text, pattern.substring(2)) ||
                    (first_match && isMatch(text.substring(1), pattern)));
        } else {
            return first_match && isMatch(text.substring(1), pattern.substring(1));
        }
    }
}

 

但是这毕竟又不是走迷宫,分析过程我们发现,对于字符串mississippi和mis*is*ip*.,如果issippi匹配成功的话,判断sissippi就不用整体判断一遍,也就是说,子问题的答案可以复用。

于是根据算法导论中作图(做出来就是一个二维表),使用二维数组来存储中间结果,就可以使用更低的时间复杂度来完成这个题目。由于每一步都在填这个二维表,时间复杂度很显然就是O(TP)。(至于状态,状态转移方程之类严谨的东西,之后再补充吧)

bool isMatch(const string& s,const  string& p)
{
    mem = vector<vector<int>>(s.size() + 1, vector<int>(p.size() + 1, -1));
    return doMatch(s, 0, p, 0);
}
bool doMatch(const string& s,int sIndex, const string& p, int pIndex)
{
	if (mem[sIndex][pIndex] != -1)
	{
		return mem[sIndex][pIndex];
	}
	bool res;
    if(pIndex >= p.size()) res = (sIndex >= s.size());
    else
    {
        bool currentMatch = (sIndex < s.size() && (s[sIndex] == p[pIndex] || p[pIndex] == '.'));
        if(pIndex+1 < p.size() && p[pIndex+1] =='*')
        {
            res = doMatch(s, sIndex, p, pIndex+2) || 
                currentMatch&&doMatch(s, sIndex + 1, p, pIndex); 
        }
        else
        {
            res = currentMatch&&doMatch(s, sIndex+1, p, pIndex + 1);
        }
    }
    mem[sIndex][pIndex] = res;
    return res;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值