📜  门| GATE CS 2020 |问题 6(1)

📅  最后修改于: 2023-12-03 15:12:37.390000             🧑  作者: Mango

门 GATE CS 2020 问题 6

本题目是关于动态规划的,需要对于给定的字符串和模式串进行匹配的问题进行求解。在这个过程中,我们需要利用动态规划的思想求解左侧字符串与右侧模式串是否可以匹配成功的问题。

问题描述

给定一个字符串 $s$ 和一个模式串 $p$,实现一个方法 isMatch(s: str, p: str) -> bool,用以判断 $s$ 是否匹配 $p$。

其中:

  • $s$ 可以包含任意字符集合;
  • $p$ 可以包含任意字符集合,以及特殊字符 *?
  • * 表示匹配任意数量的任意字符,包括零个字符;
  • ? 表示匹配单个任意字符。

注意:

  • $p$ 中不会同时出现字符 *?
  • 对 s 和 p 无需进行预处理。
示例

示例 1:

输入:s = "aa",p = "a"

输出:false

解释:"a" 无法匹配 "aa" 整个字符串。

示例 2:

输入:s = "aa",p = "*"

输出:true

解释:'*' 代表可以匹配任意字符任意数量,所以 "aa" 可以被匹配成功。

示例 3:

输入:s = "cb",p = "?a"

输出:false

解释:'?' 代表需要匹配一个字符,而 "cb" 的第二个位置是 'b' 不是 'a', 所以匹配不成功。

题解

这道题目可以采用动态规划的思路求解,具体可以定义一个二维数组 $dp$,其中 $dp[i][j]$ 表示 $s[:i]$ 是否能被 $p[:j]$ 匹配成功。我们可以考虑如下几种情况:

  • 如果 $s[i]=p[j]$ 或者 $p[j]$ 为 '?',那么 $s[:i]$ 与 $p[:j]$ 可以匹配成功,即 $dp[i][j] = dp[i-1][j-1]$。
  • 如果 $p[j] = '*'$,那么它可以匹配空串,也可以匹配任意数量的字符。因此,对于 $dp[i][j]$,它等于 $dp[i-1][j]$ 或者 $dp[i][j-1]$ 的结果。

最后的答案即为 $dp[m][n]$,其中 $m$ 和 $n$ 分别为 $s$ 和 $p$ 的长度。

代码实现如下:

class Solution:
    def isMatch(self, s: str, p: str) -> bool:
        s_len, p_len = len(s), len(p)
        dp = [[False] * (p_len + 1) for _ in range(s_len + 1)]
        dp[0][0] = True
        for i in range(1, p_len + 1):
            if p[i - 1] == '*':
                dp[0][i] = dp[0][i - 1]
        for i in range(1, s_len + 1):
            for j in range(1, p_len + 1):
                if s[i - 1] == p[j - 1] or p[j - 1] == '?':
                    dp[i][j] = dp[i - 1][j - 1]
                elif p[j - 1] == '*':
                    dp[i][j] = dp[i][j - 1] or dp[i - 1][j]
        return dp[s_len][p_len]

代码使用了 Python 的方式实现,但是思路是比较容易理解的。在此方法中,我们首先定义了一个 $dp$ 数组用于存储匹配状态,并将初始状态设置为 $dp[0][0]=True$。

然后我们进入两重循环,逐步求解左侧字符串是否能够匹配右侧模式串。其中的 $dp[i][j]$ 会依据上述的情形被不断更新,最后返回 $dp[slen][plen]$ 即可。

因此,这道算法的时间复杂度为 $O(mn)$,其中 $m$ 和 $n$ 分别为输入字符串的长度。可以通过大量的测试数据验证其正确性。