LeetCode10-正则表达式匹配-python

题目描述:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
思路一:递归

递归的终止条件:

(1)如果s字符串的长度为0,如果此时字符串p当且仅当有形如"a* b* c* d* e*"这样的格式时,返回true;否则,返回false。

(2)如果s字符串的长度不为0,而p字符串的长度为0,返回false。

递归的过程:

(1)如果s的最后一个字符与p的最后一个字符相等,或者说p的最后一个字符为".",那么我们直接看字符串s中除去最后一个字符的字符串能否与字符串p中除去最后一个字符的字符串相匹配。

(2)如果p的最后一个字符为"*",这种情况比较复杂,又分为两种情况。

a.如果s的最后一个字符既不与p的最后第二个字符相等,p的最后第二个字符也不为".",那么我们直接看字符串s中除去最后一个字符的字符串能否与字符串p中除去最后两个字符的字符串相匹配。

b.如果s的最后一个字符与p的最后第二个字符相等,或者说p的最后第二个字符为".",,这种情况比较复杂,又分为三种情况。

b-1:我们看字符串s中除去最后一个字符的字符串能否与字符串p相匹配(即把s中的最后一个字符与p的最后一个字符(*)相匹配)。

b-2:我们看字符串s能否与字符串p中除去最后一个字符的字符串相匹配(即把s中的最后一个字符与p的最后第二个字符相匹配)。

b-3:我们看字符串s中除去最后一个字符的字符串能否与字符串p中除去最后两个字符的字符串相匹配(直接舍去p中的最后两个字符)。

只要上述b-1、b-2、b-3三种情况中有一种情况相匹配,我们就返回true。如果三种情况都不匹配,我们就返回false。

每一次递归的时间复杂度是O(1)级别的,我们最多需要递归m * n次,其中m为字符串s的长度,n为字符串p的长度,时间复杂度是O(m * n)。由于递归存在对系统栈的调用,因此空间复杂度与递归深度成正比,而递归的最大深度是m * n,因此空间复杂度是O(m * n)。

python解法

class Solution:
    def isMatch(self, s: str, p: str) -> bool:
        m= len(s)
        n= len(p)
        if (m!= 0 and n== 0):
            return False
        
        if m== 0:
            if n%2==1:
                return False
            i= 1
            while (i< n and p[i]=='*'):
                i= i+2
            if i== n+1:
                return True
            else:
                return False
            
        if s[m-1]==p[n-1] or p[n-1]=='.':
            return self.isMatch(s[0:m-1],p[0:n-1])
        if p[n-1]=='*':
            if s[m-1]!= p[n-2] and p[n-2]!='.':
                return self.isMatch(s,p[0:n-2])
            else:
                return self.isMatch(s,p[0:n-1]) or self.isMatch(s,p[0:n-2]) or self.isMatch(s[0:m-1],p)
        
        return False
        

思路二:动态规划

用题给的示例4来模拟递归的过程如下图所示
在这里插入图片描述
图中紫色椭圆所在区域就是递归过程中出现的重叠子问题,既然发现了重叠子问题,那么肯定就可以用动态规划来解决!而动态规划的关键是状态定义的合适选取以及发现正确的状态转移。

状态定义:f(x, y)------字符串s中[0, x - 1]范围内的字符串能否匹配字符串p中[0, y - 1]范围内的字符串

状态转移:

(1)如果p(y) == ‘.’, f(x, y) = f(x - 1, y - 1)。

(2)如果p(y) == s(x), f(x, y) = f(x - 1, y - 1)。
(3)如果p(y) == '’,
a.如果s(x) == p(y - 1) || p(y - 1) == ‘.’,
a-1:使用’
‘号进行匹配——f(x - 1, y)
a-2:只使用’‘号前面的那个字符匹配,不使用’‘匹配——f(x, y - 1)
a-3:’*'号前面的那个字符在匹配的过程当中一个都不使用——f(x, y - 2)
f(x, y) = f(x - 1, y) || f(x, y - 1) || f(x, y - 2)。
b.如果s(x) != p(y - 1) && p(y - 1) != ‘.’
*号前面的那个字符在匹配的过程当中一个都不使用,f(x, y) = f(x, y - 2)。

为了处理s为空的情形,我们定义状态转移数组matched的行数和列数分别为s.length() + 1和p.length() + 1。显然我们有matched[0][0] = true。对于第0行,相当于字符串s为空,就是思路一中递归的终止条件(1)中的情形。

此思路的时间复杂度是O(m * n),其中m为字符串s的长度,n为字符串p的长度,但相比思路一省略了很多重叠子问题的重复计算。空间复杂度是一个boolean类型的m * n的数组,因此空间复杂度是O(m * n)。

python解法

class Solution:
    def isMatch(self, s: str, p: str) -> bool:
        #if not s or not p:
            #return False
        s_len = len(s)
        p_len = len(p)
        dp = [[False] * (p_len + 1) for _ in range(s_len + 1)]
        print(dp)
        dp[0][0] = True
        for i in range(p_len):
            if p[i] == "*" and dp[0][i - 1]:
                dp[0][i + 1] = True
        #print(dp)
        for i in range(s_len):
            for j in range(p_len):
                if p[j] == s[i] or p[j] == ".":
                    dp[i + 1][j + 1] = dp[i][j]
                elif p[j] == "*":
                    if p[j - 1] != s[i]:
                        dp[i + 1][j + 1] = dp[i + 1][j - 1]
                    if p[j-1] == s[i] or p[j-1] == ".":
                        dp[i+1][j+1] = (dp[i][j+1] or dp[i+1][j]   or  dp[i+1][j-1])
        #print(dp)
        return dp[-1][-1]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值