返回

彻底破解Leetcode Hard - 通配符匹配难题,掌握字符匹配核心技巧

前端

征服通配符匹配难题:掌握字符匹配的核心技巧

前言

欢迎来到通配符匹配的迷人世界,这是LeetCode上众所周知的Hard难度难题。准备好在程序员小明的陪伴下踏上解题之旅吧!我们将从零开始,深入解析这道题,手把手带你掌握字符匹配的核心技巧。

什么是通配符匹配?

通配符匹配是一种强大的机制,允许你使用通配符字符(如“?”和“*”)来表示任意字符或字符串序列。这使得你可以创建灵活的模式,与广泛的输入字符串匹配。

题目剖析

在本题中,你需要判断一个输入字符串 s 是否匹配一个给定的字符模式 p。模式 p 可能包含以下通配符字符:

  • ?:匹配任何单个字符。
  • *:匹配任意数量的字符(包括空字符串)。

动态规划求解

解决通配符匹配的最佳方法是使用动态规划。我们定义一个二维数组 dp,其中 dp[i][j] 表示字符串 s 的前 i 个字符和字符模式 p 的前 j 个字符是否匹配。

填充 dp 数组的规则如下:

  • dp[i][0]false,因为任何字符串都不能匹配空字符模式。
  • dp[0][j]truep[j]* 时,因为空字符串可以匹配任意数量的字符,包括空字符串。
  • s[i] == p[j]p[j] == '?' 时,dp[i][j]dp[i-1][j-1]
  • p[j] == '*' 时,dp[i][j]dp[i-1][j]dp[i][j-1]

代码实现

有了动态规划算法,我们可以用Python轻松实现通配符匹配:

def is_match(s, p):
    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 + 1):
        dp[0][j] = dp[0][j - 1] and p[j - 1] == '*'

    for i in range(1, m + 1):
        for j in range(1, n + 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 - 1][j] or dp[i][j - 1]

    return dp[m][n]

示例

让我们看一个示例:

s = "aa"
p = "a*"

填充 dp 数组后,我们得到:

[
  [True, True, True],
  [False, True, True]
]

由于 dp[2][3]True,因此字符串 "aa" 匹配模式 "a*"

结语

掌握通配符匹配技巧将使你能够解决各种字符串匹配问题。这道LeetCode题看似复杂,但通过一步一步的解析和代码实现,你已经彻底征服了它。

常见问题解答

  • 问:为什么当 p[j]* 时,dp[i][j]dp[i-1][j]dp[i][j-1]

    • 答: 因为 * 可以匹配任意数量的字符,包括空字符串。所以,如果 s[i]p[j] 不匹配,我们有两种选择:跳过 s[i] 或跳过 p[j] *
  • 问:在填充 dp 数组时,为什么需要处理边界情况?

    • 答: 边界情况确保当字符串或模式为空时,算法的行为正确。
  • 问:是否有优化算法来解决通配符匹配问题?

    • 答: 是的,有更有效率的算法,如Knuth-Morris-Pratt算法,可以减少时间复杂度。
  • 问:通配符匹配在实际应用中有什么用?

    • 答: 通配符匹配广泛用于文件搜索、正则表达式和字符串处理等各种应用中。
  • 问:如何处理更复杂的通配符字符集?

    • 答: 算法可以根据需要扩展,以支持更多通配符字符。