10. Regular Expression Matching

https://leetcode.com/problems/regular-expression-matching/description/

题目大意:给一个字符串s和模式串p,求s是否匹配p
这里要注意的是“*”表示前面的字符可以重复0到无数次,并不是传统意义上的通配符。

解题思路1(递归):把x*(x为任意字符),当做一个整体,这是最难处理的部分,因为x可以重复0到无数次。
我们先来判断p是否为空,若为空则根据s的为空的情况返回结果。当p的第二个字符为*号时,由于*号前面的字符的个数可以任意,可以为0,那么我们先用递归来调用为0的情况,就是直接把这两个字符去掉再比较,或者当s不为空,且第一个字符和p的第一个字符相同时,我们再对去掉首字符的s和p调用递归,注意p不能去掉首字符,因为*号前面的字符可以有无限个;如果第二个字符不为*号,那么我们就老老实实的比较第一个字符,然后对后面的字符串调用递归

代码:

class Solution:
    def isMatch(self, s, p):
        """
        :type s: str
        :type p: str
        :rtype: bool
        """
        if not p:
            return not s
        #为了使代码简洁,第一位字符匹配的结果用first_match代替
        first_match = bool(s) and (s[0] == p[0] or p[0] == '.')

        if len(p) >= 2 and p[1] == '*':  #如果在p中检测到“x*”型字段
            return self.isMatch(s, p[2:]) or first_match and self.isMatch(s[1:], p)
        else:
            return first_match and self.isMatch(s[1:], p[1:])

解题思路2(DP):
用二维矩阵dp记录,dp[i][j]的布尔值表示s[0..i)是否与p[0..j)匹配(注意右边是开区间),初始值为False。
初始状态:令dp[0][0]为true,i=0表示s为空,j=0表示p为空,s、p都为空的时候是匹配的。
重点还是处理x*类型的p串:
例如
判断“a”和“aa*”是否匹配

s=“a a a” , i=1(注意前面表述是开区间)
   ^
p=“a a *” , j=3
       ^

若1)a*匹配0次,则j回退两位,i不动:

s=“a a a” , i=1
   ^
p=“a a *” , j=1
   ^

若“a”和“a”匹配,则“a”和“aa*”匹配。
即dp[i][j]的状态和dp[i][j-2]是相同的,推导得dp[i][j] = dp[i][j-2]

判断“aa”和“aa*”是否匹配

s=“a a a” , i=2
     ^
p=“a a *” , j=3
       ^

2)a*匹配1次,则i回退1位,j回退2位

s=“a a a” , i=1
   ^
p=“a a *” , j=1
   ^    

若“a”和“a”匹配,且“a”和“aa*”匹配,则“aa”和“aa*”匹配。
“a”和“a”匹配的条件为:s[i-1] == p[j-2] ,或p[j-2] == ‘.’(单个字符匹配)
“a”和“aa*”匹配的条件:有点抽象,因为a*可以匹配0到无数个a,因此要保证上一个状态是匹配的(j指向*,不动;i回退一位),当前状态才能匹配。上一个状态为:dp[i-1][j] = true
综上,a*匹配一次的条件:

dp[i-1][j] and (s[i-1] == p[j-2] or p[j-2] == '.')
1)和2)情况是并列的。

3)单个字符匹配:
两种,一种是相等匹配,另一种是‘.’匹配。而且上一个状态dp[i-1][j-1]匹配
条件:

dp[i-1][j-1] and (s[i-1] == p[j-1] or p[j-1] == '.')
此外还要注意下标,要保证i>0
因为有p[j-1] == ‘*’的限制,因此j不用过多限制
i从0到m
j从1到n,因为j=0时p为空串,除了空以外的所有s都不匹配

class Solution:
    def isMatch(self, s, p):
        """
        :type s: str
        :type p: str
        :rtype: bool
        """
        m,n = len(s), len(p)
        dp = [[False] * (n+1) for _ in range(m+1)]
        dp[0][0] = True
        for i in range(m+1):
            for j in range(1, n+1):
                if p[j-1] == '*':
                    dp[i][j] = dp[i][j-2] or (i>0 and dp[i-1][j] and (s[i-1] == p[j-2] or p[j-2] == '.'))
                else:
                    dp[i][j] = i>0 and dp[i-1][j-1] and (s[i-1] == p[j-1] or p[j-1] == '.')
        print(dp)
        return dp[m][n]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值