pthon做题日记(3)

引言

        这篇主要就leetcode中的第十题写一下自己的理解和笔记,因为自己本身的代码能力不算很有基础,因此在理解这道题的解题逻辑上花了一些时间。

第十题

题目描述

        第十题的题目描述是正则表达式匹配,也就是给定一个字符串,再给定一种字符串匹配模式,看看给定的字符串匹配模式是否能够涵盖给定的字符串,也就是按照字符串匹配模式,能不能得到给定的字符串。对于匹配模式有如下定义:

        1. 匹配模式中的“.”能够匹配任意字符

        2. 匹配模式中的“*”代表其前面一个字符能够匹配匹配零次或多次,举个例子也就是“a*”这样一个匹配模式能够匹配零个a或多个a。

代码思路

        这道题目采用动态规划的思想进行编写代码,动态规划的核心是用小问题的解,推导出大问题的解。先来看最终得到的代码:

class Solution:
    def isMatch(self, s: str, p: str) -> bool:
        m, n = len(s), len(p)
        # 初始化 DP 表
        dp = [[False] * (n + 1) for _ in range(m + 1)]
        dp[0][0] = True  # 空字符串和空模式匹配

        # 初始化第一行(s 为空的情况)
        for j in range(2, n + 1):
            if p[j - 1] == '*':
                dp[0][j] = dp[0][j - 2]

        # 填充 DP 表
        for i in range(1, m + 1):
            for j in range(1, n + 1):
                if p[j - 1] == s[i - 1] or p[j - 1] == '.':
                    dp[i][j] = dp[i - 1][j - 1]
                elif p[j - 1] == '*':
                    dp[i][j] = dp[i][j - 2] or (dp[i - 1][j] and (s[i - 1] == p[j - 2] or p[j - 2] == '.'))

        return dp[m][n]

        首先创建一个DP表,并且初始化使其每个元素都为False,DP表中的每个元素代表着s字符串的前i个字符能否与模式p的前j个字符相匹配,举例来说就是dp[2][4]即s字符的前两个字符能否与模式p的前4个字符组成的模式相匹配,按照这样的定义,最终dp[m][n]元素的值即为最终所要得到的本题答案。

        本题理解上较为困难的应该是DP表中各个元素之间的转换关系,即状态转移关系。

  1. 首先是普通字符或“.”的情况:

    如果p[j-1] == s[i-1]或者p[j-1] == '.',说明当前字符是可以相互匹配的,这时dp[i][j]的值就取决于前一个状态dp[i-1][j-1],也就是说dp[i][j] = dp[i-1][j-1]。 也就是说如果当前字符能够匹配,且前面的字符串都能够匹配的情况下,整体才能够完全匹配。
     
  2. "*"的情况:

        因为“*”具有匹配零次或多次的用法,因此将其分为两部分分别进行讨论:

  • 首先是匹配零次的情况,匹配零次就意味着其本身及其前面的字符不存在实际意义,因此可以将这两个字符忽略,此时其状态就取决于dp[i][j-2]是否为True。
  • 其次是匹配1次或多次的情况:如果s[i-1]能够和p[j-2]相互匹配(即s[j-1] == p[j-2]或者p[j-2] == '.'的情况下),并且有dp[i-1][j]为True,则也可以相互匹配,即状态为True。

将上述这两种情况综合在一起就形成如下这行代码:

dp[i][j] = dp[i][j-2] or (dp[i-1][j] and (s[i-1] == p[j-2] or p[j-2] == '.'))

在理解的过程中要注意DP表中的下标与字符串中下标的对应情况,DP表中的i,j就代表实际的值,而字符串中需要将i,j分别减1以获得相对应的第i,j个字符元素。 

总结

        本题采用动态规划思想源于子问题的重叠,即判断某一部分是否匹配时需要用到它们更短的前缀的匹配结果,这些子问题会被重复用到,适合用DP表保存结果,避免重复计算。只要所有的子问题都正确得推导得到结果,那么整体也能够得到正确的结果。根据题目的描述可以得到相对清晰的状态转移关系,因此适合采用动态规划的思想对问题进行求解。

        因为自身的代码能力还不够,因此借助了一些题解对题目和代码进行理解。期待继续充盈自己!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值