10. 正则表达式匹配(Regular Expression Matching)

题解

递归

递归函数 i s M a t c h ( s , p ) isMatch(s,p) isMatch(s,p) s s s表示待匹配字符, p p p表示字符规律

  1. p p p为空,此时返回 s s s是否为空。表示若字符规律已经为空,若 s s s还不为空,此时匹配失败。若为空,表示匹配成功。
  2. 定义 p r e pre pre表示 s s s p p p第一位是否匹配成功。 匹配条件: s s s不能为空且 p [ 0 ] = = s [ 0 ]   o r   " . " p[0]==s[0]\ or\ "." p[0]==s[0] or "."。表示 p p p的第一位等于 s s s的第一位,或者 p [ 0 ] = = " . " p[0]=="." p[0]=="."可以匹配所有字符。
  3. p p p中有 ∗ * 字符,条件 l e n ( p ) > = 2   a n d   p [ 1 ] = = ∗ len(p)>=2\ and\ p[1]==* len(p)>=2 and p[1]==,表示第二位为 ∗ * 。即有字符和 ∗ * 相连。对应两种情况。
    • 跳过这两个字符,表示这个字符出现零次。即 i s M a t c h ( s , p [ 2 : ] ) isMatch(s,p[2:]) isMatch(s,p[2:])—此处不理解,看我的注意!
    • 首位匹配成功,继续匹配 s [ 1 : ] s[1:] s[1:] p p p,即 p r e   a n d   i s M a t c h ( s [ 1 : ] , p ) pre\ and\ isMatch(s[1:],p) pre and isMatch(s[1:],p)
  4. 若无 ∗ * 则,继续匹配,返回 p r e   a n d   i s M a t c h ( s [ 1 : ] , p [ 1 : ] ) pre\ and\ isMatch(s[1:],p[1:]) pre and isMatch(s[1:],p[1:])

注意!
字符 + ∗ +* +是一个整体,表示这个字符出现0次或者多次! 经过我的测试,测试用例*不能单独出现,一定跟在字符后
如下两种测试用例,前一种会报错,后一种不会。

在这里插入图片描述
在这里插入图片描述

复杂度分析

  • 时间复杂度: O ( ( S + P ) ∗ 2 S + P 2 ) O\left((S+P)*2^{S+\frac{P}{2}}\right) O((S+P)2S+2P),具体分析略。 S S S表示 s s s的长度, P P P表示 p p p的长度。
  • 空间复杂度: O ( ( S + P ) ∗ 2 S + P 2 ) O\left((S+P)*2^{S+\frac{P}{2}}\right) O((S+P)2S+2P)

Python

class Solution:
    def isMatch(self, s: str, p: str) -> bool:
        if not p:
             return not s
        first = bool(s) and p[0] in {s[0], '.'}
        if len(p) >= 2 and p[1] == '*':
            return self.isMatch(s, p[2:]) or first and self.isMatch(s[1:], p)
        else:
            return first and self.isMatch(s[1:], p[1:])

Java(待完成)

动态规划法

重叠子问题结构

  1. 初始化 s s s的长度 S S S p p p的长度 P P P

  2. 初始化哈希表 m e m o = { } memo=\{\} memo={},键为 ( i , j ) (i,j) (i,j),值为 T r u e   o r   F a l s e True\ or\ False True or False,表示 s [ 0 , . . . , i ] s[0,...,i] s[0,...,i] p [ 0 , . . . , j ] p[0,...,j] p[0,...,j]是否匹配。

  3. 定义递归函数 d p ( i , j ) dp(i,j) dp(i,j) i i i为当前 s s s的匹配位置, j j j p p p的匹配位置。

    • ( i , j ) (i,j) (i,j)出现在 m e m o memo memo中,表示当前子问题,之前已经处理过,直接返回对应的值, m e m o [ ( i , j ) ] memo[(i,j)] memo[(i,j)]
    • j = = P j==P j==P,说明 p p p已经匹配完,若此时 s s s还有字符未匹配,则返回 F a l s e False False,若 s s s也匹配完,则返回 T r u e True True。即返回 i = = S i==S i==S
    • 定义 p r e pre pre表示当前 p p p s s s的首位是否匹配。条件: i < S i<S i<S表示 s s s是否遍历完。且 p [ j ] p[j] p[j]是否等于 s [ i ] s[i] s[i] " . " "." "." p r e = i < S   a n d   p [ j ]   i n   { s [ i ] , " . " } pre= i<S\ and\ p[j]\ in\ \{s[i],"."\} pre=i<S and p[j] in {s[i],"."}
    • 判断是否存在 ∗ * 字符,条件: j < = P − 2 j<=P-2 j<=P2表示是否还剩两个字符以上,且 p [ j + 1 ] p[j+1] p[j+1] ∗ *
      • 跳过这两个字符,表示匹配 0 0 0次, d p ( i , j + 2 ) dp(i,j+2) dp(i,j+2)
      • 首位匹配成功,继续匹配下一位, p r e   a n d   d p ( i + 1 , j ) pre\ and\ dp(i+1,j) pre and dp(i+1,j)
      • t m p = d p ( i , j + 2 )   o r   p r e   a n d   d p ( i + 1 , j ) tmp=dp(i,j+2)\ or\ pre\ and\ dp(i+1,j) tmp=dp(i,j+2) or pre and dp(i+1,j)
    • 否则, t m p = d p ( i + 1 , j + 1 ) tmp=dp(i+1,j+1) tmp=dp(i+1,j+1)
    • 更新 m e m o memo memo m e m o [ ( i , j ) ] = t m p memo[(i,j)]=tmp memo[(i,j)]=tmp
    • 返回 t m p tmp tmp
  4. 返回 d p ( 0 , 0 ) dp(0,0) dp(0,0)

复杂度分析

  • 时间复杂度: O ( S ∗ P ) O\left(S*P\right) O(SP)
  • 空间复杂度: O ( S ∗ P ) O(S*P) O(SP)

Python

class Solution:
    def isMatch(self, s: str, p: str) -> bool:
        S=len(s)
        P=len(p)
        memo={}
        def dp(i,j):
            if((i,j) in memo):
                return memo[(i,j)]
            if(j==P):
                return i==S
            pre=i<S and p[j] in {s[i],"."}
            if(j<=P-2 and p[j+1]=="*"):
                tmp=dp(i,j+2) or pre and dp(i+1,j)
            else:
                tmp=pre and dp(i+1,j+1)
            memo[(i,j)]=tmp
            return tmp
        return dp(0,0)

在这里插入图片描述

Java(待完成)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值