leetcode题目10之正则表达式匹配


Given an input string (s) and a pattern (p), 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).

Note:

  • s could be empty and contains only lowercase letters a-z.

  • p could be empty and contains only lowercase letters a-z, and characters like . or *
解答:采用动态规划的方法

用dp(i,j)计算text[i:]与patter[j:]匹不匹配.最终要得到的结果就是dp(0,0)。如果i,j已经计算过,就保存起来,直接返回。没有计算过,就需要计算。

如果j已经超过了最后一个字符,那么只有当i也超过最后一个字符时,才是匹配。patten为空的情况也包含在这里。因为两个字符串匹配,最终肯定是要一起结束判断的。

如果还没有判断完,就分为两种情况。

第一种是带星号的。这是j后面至少还需要有一个字符,即j<len(pattern)-1且pattern[j+1] == '*'

此时匹配又分为两种情况:1)text中有0个*前面的字符,那么此时的dp(i,j)直接等于dp(i,j+2),即*和他前面的不需要再判断。

2)text中有多个1或多个*前面的字符,那么此时首先须保证text[i]和text[j]匹配,然后再把text[i]去掉后判断即可。即text[i+1:]与pattter[j:]是否匹配

第二种情况是单字符的匹配,即没有星号的匹配。j可能等于pattern最后一个字符位置(因为大于最后一个字符位置的情况在前面被排除了)或pattern[j+1]不是星号。此时只要i还没越界,切pattern[j]==text[i]或.即可。呢么dp(i,j) == dp(i+1,j+1),即当前字符text[i]和pattern[j]匹配,只要后面也匹配即可。

每次把结果保存起来,可以方便下次如果用到同样的数的话不用再次重复计算,大大提高效率

class Solution(object):
    def isMatch(self, text, pattern):
        memo = {}
        def dp(i, j):
            if (i, j) not in memo:
                if j == len(pattern):
                    ans = i == len(text)
                else:
                    first_match = i < len(text) and pattern[j] in {text[i], '.'}
                    if j+1 < len(pattern) and pattern[j+1] == '*':
                        ans = dp(i, j+2) or first_match and dp(i+1, j)
                    else:
                        ans = first_match and dp(i+1, j+1)


                memo[i, j] = ans
            return memo[i, j]


        return dp(0, 0)


第二种方法:

递归

class Solution(object):
    def isMatch(self, s, p):
        """
        :type s: str
        :type p: str
        :rtype: bool
        """
        #如果只有.只需要一个元素一个元素比较,或者相等或者p中是.
        #如果有*,*要与前一个元素组合起来比较
        #因为采用递归形式,因此分为两种情况,第二个字符是*
        #第二个字符不是*(又包括只有一个字符和第二个字符不是*两种情况)
        
        #先处理特殊情况
        if not p: #包括p为None和p的长度为0两种情况
            return not s #若s也为空则匹配,否则不匹配
        #第一个字符匹配,因为此时p不为空,所以s也不能为空
        #或者等于p[0],或者为‘.’
        first_match = bool(s) and p[0] in (s[0],'.')
        if len(p) >= 2 and p[1]=='*':
            #第二个字符是*时,他前面的字母可以出现0次,此时只需要直接把*和前面的字符去掉递归即可
            #或者是它前面的字符出现好多次,此时只要第一个字符匹配,然后每次去掉一个s的字母与原来的模式p匹配即可
            return self.isMatch(s,p[2:]) or (first_match and self.isMatch(s[1:],p))
        else:
            #p的长度为1(因为0已经在最开始排除) 或者第二个字符不是*
            #与没有*时一样,只要第一个一样,然后去掉首字母后在比较,都相等则匹配
            return first_match and self.isMatch(s[1:],p[1:])

猜你喜欢

转载自blog.csdn.net/welight_blue/article/details/80545847
今日推荐