动态规划-052-正则表达式匹配

题目描述

请实现一个函数用来匹配包括’.‘和’‘的正则表达式。模式中的字符’.‘表示任意一个字符,而’'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a""ab*ac*a"匹配,但是与"aa.a""ab*a"均不匹配

分析

  • 分析递归
    每次从字符串里取出一个字符与模式中的字符匹配,如果模式中的字符是‘.’,它可以匹配字符串中的任意字符,如果不是,那么如果它与字符串中的字符相等则匹配。当字符串的字符和模式的字符匹配时,接着匹配后面的字符。总的分为两种情况。
    1. 接下来考虑如果模式串存在第二个字符并且第二个字符是"*":
      1. 如果模式中的第一个字符和字符串中的第一个字符不匹配(两种情况,不等或者字符串为None),则在模式上后移两个字符,相当于忽略‘’和它前面的字符,因为‘’可以匹配字符串中的0个字符;
      2. 如果模式中的第一个字符和字符串中的第一个字符匹配,则字符串后移一个字符,而在模式上又有两种选择:
        1. 只模式串上后移两个字符。(例如字符串"ab"和模式"a*ab"
        2. 模式保持不变,字符串后移一个字符。(例如字符串"aabbba"和模式"aab*a"
    2. 考虑模式中的第二个字符不是‘*’:
      1. 如果字符串中的第一个字符和模式中的第一个字符相匹配,那么字符串和模式都后移一个字符,然后匹配剩余的字符串和模式;
      2. 如果字符串中的第一个字符和模式中的第一个字符不匹配,则直接返回false

代码

# -*- coding:utf-8 -*-
class Solution:
    # s, pattern都是字符串
    def match(self, s, pattern):
        # write code here
        if not s and not pattern:
            return True
        
        if s and not pattern:
            return False
        
        if not s and pattern:
            if len(pattern)>=2 and pattern[1] == '*':
                return self.match(s, pattern[2:])
            else:
                return False
            
        if s and pattern:
            if len(pattern)>=2 and pattern[1] == '*':
                if s[0] == pattern[0] or pattern[0] == '.':
                    return self.match(s[1:], pattern) or self.match(s, pattern[2:])
                else:
                    return self.match(s, pattern[2:])
            else:
                if pattern[0]==s[0] or pattern[0] == '.':
                    return self.match(s[1:], pattern[1:])
                else:
                    
                    return False
class Solution:
    def isMatch1(self, s: str, p: str) -> bool:
        '''
        dp[i][j] 代表s[:i] p[:j]是否匹配

        dp[i][j] = dp[i-1][j-1]  if s[i] == p[j] or p[j] == '.'  match
                 = dp[i][j-2]              不匹配                                p[j] == '*'
                 = dp[i-1][j-2]            匹配一个字符      s[i]=p[j−1]          p[j] == '*'
                 = dp[i-2][j-2]            匹配两个字符     s[i−1]=s[i]=p[j−1]     p[j] == '*'
                 ...

                 核心重点:字母 * 星号的组合在匹配的过程中,本质上只会有两种情况:
                 1. 匹配 s 末尾的一个字符,将该字符扔掉,而该组合还可以继续进行匹配;
                 2. 不匹配字符,将该组合扔掉,不再进行匹配。

        dp[i][j] = dp[i-1][j-1]  if s[i] == p[j] or p[j] == '.'  令为 match(i, j)
                 = dp[i-1][j] or dp[i][j-2]   if p[j] == '*' and match(i, j-1)
                 = dp[i][j-2]                 if p[j] == '*' and not match(i, j-1)

        边界:  dp[0][0] True
                dp[i][0] False
                dp[0][j] 分情况讨论了, 连续偶数个 * True p = 'a*.*'

        res = dp[-1][-1]
        
        m = len(s)
        n = len(p)
        时间复杂度 O(mn)
        空间复杂度 O(mn)
        '''
        def match(i, j):
            '''
            :param i:  s 的索引
            :param j:  p 的索引
            :return: 是否单个匹配
            '''
            if j<0 :
                return False
            if s[i]==p[j] or p[j]=='.':
                return True
            else:
                return False



        m, n = len(s), len(p)
        dp = [[False]*(n+1) for _ in range(m+1)]

        # 限定边界
        dp[0][0] = True

        for j in range(1, n, 2):
            if p[j] == '*':
                dp[0][j+1] = True
            else:
                break

        # 状态转移
        for i in range(1, m+1):
            for j in range(1, n+1):
                if p[j-1] == '*':
                    if match(i-1, j-2):
                        dp[i][j] = dp[i-1][j] or dp[i][j-2]
                    else:
                        dp[i][j] = dp[i][j-2]
                else:
                    if match(i-1, j-1):
                        dp[i][j] = dp[i-1][j-1]
                    else:
                        dp[i][j] = False  # 初始化一致

        return dp[-1][-1]



    def isMatch(self, s, p):
        '''
        dp[i][j] 代表s[:i] p[:j]是否匹配

        dp[i][j] = dp[i-1][j-1]  if s[i] == p[j] or p[j] == '.'  match
                 = dp[i][j-2]              不匹配                                p[j] == '*'
                 = dp[i-1][j-2]            匹配一个字符      s[i]=p[j−1]          p[j] == '*'
                 = dp[i-2][j-2]            匹配两个字符     s[i−1]=s[i]=p[j−1]     p[j] == '*'
                 ...

                 核心重点:字母 * 星号的组合在匹配的过程中,本质上只会有两种情况:
                 1. 匹配 s 末尾的一个字符,将该字符扔掉,而该组合还可以继续进行匹配;
                 2. 不匹配字符,将该组合扔掉,不再进行匹配。

        dp[i][j] = dp[i-1][j-1]  if s[i] == p[j] or p[j] == '.'  令为 match(i, j)
                 = dp[i-1][j] or dp[i][j-2]   if p[j] == '*' and match(i, j-1)
                 = dp[i][j-2]                 if p[j] == '*' and not match(i, j-1)

        边界:  dp[0][0] True
                dp[i][0] False
                dp[0][j] 分情况讨论了, 连续偶数个 * True p = 'a*.*'

        res = dp[-1][-1]
		
		m = len(s)
		n = len(p)
		时间复杂度 O(mn)
		空间复杂度 O(n) 
        空间优化
        '''
        def match(i, j):
            '''
            :param i:  s 的索引
            :param j:  p 的索引
            :return: 是否单个匹配
            '''
            if j<0 :
                return False
            if s[i]==p[j] or p[j]=='.':
                return True
            else:
                return False



        m, n = len(s), len(p)
        dp = [False]*(n+1)

        # 限定边界
        dp[0] = True

        for j in range(1, n, 2):
            if p[j] == '*':
                dp[j+1] = True
            else:
                break
        # 状态转移
        for i in range(1, m+1):
            last = True if i==1 else False
            dp[0] = False
            for j in range(1, n+1):
                temp = dp[j]
                if p[j-1] == '*':
                    if match(i-1, j-2):
                        dp[j] = dp[j] or dp[j-2]
                    else:
                        dp[j] = dp[j-2]
                else:
                    if match(i-1, j-1):
                        dp[j] = last
                    else:
                        dp[j] = False
                last = temp

        return dp[-1]


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TransientYear

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值