LeetCode题目44:通配符匹配【python】

简介: LeetCode题目44:通配符匹配【python】

作者介绍:10年大厂数据\经营分析经验,现任大厂数据部门负责人。

会一些的技术:数据分析、算法、SQL、大数据相关、python

欢迎加入社区:码上找工作

作者专栏每日更新:

LeetCode解锁1000题: 打怪升级之旅

python数据分析可视化:企业实战案例

备注说明:方便大家阅读,统一使用python,带必要注释,公众号 数据分析螺丝钉 一起打怪升级

问题描述

给你一个输入字符串 (s) 和一个字符模式 § ,请你实现一个支持 ‘?’ 和 ‘’ 匹配规则的通配符匹配:
‘?’ 可以匹配任何单个字符。
'
’ 可以匹配任意字符序列(包括空字符序列)。

判定匹配成功的充要条件是:字符模式必须能够 完全匹配 输入字符串(而不是部分匹配)。

示例 1:

输入:s = “aa”, p = “a”

输出:false

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

示例 2:

输入:s = “aa”, p = ""
输出:true
解释:'
’ 可以匹配任意字符串。

示例 3:

输入:s = “cb”, p = “?a”

输出:false

解释:‘?’ 可以匹配 ‘c’, 但第二个 ‘a’ 无法匹配 ‘b’。

方法一:动态规划

解题步骤
  1. 初始化状态数组:创建一个二维布尔数组 ( dp ) ,其中 ( dp[i][j] ) 表示字符串 ( s ) 的前 ( i ) 个字符是否与模式 ( p ) 的前 ( j ) 个字符匹配。
  2. 处理边界条件
  • ( dp[0][0] = \text{True} ),两个空字符串是可以匹配的。
  • ( dp[i][0] = \text{False} ),空模式不能匹配非空字符串。
  • ( dp[0][j] ),只有当 ( p ) 的前 ( j ) 个字符全部为 ‘*’ 时才为真。
  1. 填充状态数组
  • 如果 ( p[j-1] == ‘?’ ) 或 ( s[i-1] == p[j-1] ),则 ( dp[i][j] = dp[i-1][j-1] )。
  • 如果 ( p[j-1] == ‘’ ),则 ( dp[i][j] = dp[i][j-1] )(不使用 '’) 或 ( dp[i-1][j] )(使用 ‘*’)。
  1. 返回结果:( dp[len(s)][len§] )。
python示例
def isMatch(s: str, p: str) -> bool:
    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):
        if p[j - 1] == '*':
            dp[0][j] = dp[0][j - 1]
    for i in range(1, m + 1):
        for j in range(1, n + 1):
            if p[j - 1] == '?' or s[i - 1] == 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[m][n]
# 示例调用
print(isMatch("aa", "a"))  # 输出: False
print(isMatch("aa", "*"))  # 输出: True
算法分析
  • 时间复杂度:(O(M \times N)),其中 (M) 和 (N) 分别是字符串 (s) 和模式 (p) 的长度。
  • 空间复杂度:(O(M \times N)),用于存储状态数组。

方法二:双指针

解题步骤
  1. 初始化指针:分别为字符串 ( s ) 和模式 ( p ) 设置两个指针 ( i ) 和 ( j )。
  2. 跟踪最后一个星号:使用变量记录最后匹配的 ‘*’ 的位置和对应的 ( s ) 的指针位置。
  3. 匹配字符串与模式
  • 如果当前字符匹配或 ( p[j] == ‘?’ ),则 ( i ) 和 ( j ) 都加一。
  • 如果 ( p[j] == ‘*’ ),更新星号匹配的位置,将 ( j ) 增加一,并记录 ( i ) 的位置。
  • 如果不匹配,检查是否存在之前匹配的 ‘',如果有,回溯到最后一个 '’,增加对应的 ( s ) 的指针位置。
  1. 检查剩余模式字符:所有主要字符匹配后,确保模式剩余的都是 ‘*’。
python示例
def isMatch(s: str, p: str) -> bool:
    si, pi = 0, 0
    star_idx = -1
    match = 0
    while si < len(s):
        if pi < len(p) and (s[si] == p[pi] or p[pi] == '?'):
            si += 1
            pi += 1
        elif pi < len(p) and p[pi] == '*':
            star_idx = pi
            match = si
            pi += 1
        elif star_idx != -1:
            pi = star_idx + 1
            match += 1
            si = match
        else:
            return False
    while pi < len(p) and p[pi] == '*':
        pi += 1
    return pi == len(p)
# 示例调用
print(isMatch("aa", "a"))  # 输出: False
print(isMatch("aa", "*"))  # 输出: True
算法分析
  • 时间复杂度:(O(M + N)),其中 (M) 和 (N) 分别是字符串 (s) 和模式 (p) 的长度。在最坏情况下,可能需要回溯,但平均情况下接近线性。
  • 空间复杂度:(O(1)),使用常数空间。

方法三:贪心算法

解题步骤
  1. 初始化指针:与双指针方法类似,使用贪心策略优化处理 ‘*’ 的回溯过程。
  2. 贪心匹配:使用贪心策略在遇到 ‘*’ 时尽可能地延迟匹配,优先匹配后面的字符。
  3. 最后检查:确保没有多余的非 ‘*’ 字符在模式 ( p ) 中残留。
python示例

代码结构与方法二相似,主要优化在处理 ‘*’ 的策略上,尽量减少回溯。

def isMatch(s: str, p: str) -> bool:
    si, pi = 0, 0
    star_idx = -1
    match = 0
    while si < len(s):
        if pi < len(p) and (s[si] == p[pi] or p[pi] == '?'):
            si += 1
            pi += 1
        elif pi < len(p) and p[pi] == '*':
            star_idx = pi
            match = si
            pi += 1
        elif star_idx != -1:
            pi = star_idx + 1
            match += 1
            si = match
        else:
            return False
    while pi < len(p) and p[pi] == '*':
        pi += 1
    return pi == len(p)
# 示例调用
print(isMatch("aa", "a"))  # 输出: False
print(isMatch("aa", "*"))  # 输出: True
算法分析
  • 时间复杂度:(O(M + N)),其中 (M) 和 (N) 分别是字符串 (s) 和模式 (p) 的长度。尽管存在回溯机制,但贪心策略尽可能减少不必要的回溯。
  • 空间复杂度:(O(1)),只使用了几个辅助变量,不依赖于输入大小。

方法三:贪心算法 (续)

这种方法通过贪心算法优化了处理 ‘’ 的回溯过程,通过在每次遇到 '’ 时,记录当前位置并尝试匹配后续字符,如果后续匹配失败,再回到 ‘*’ 的位置尝试更少的字符匹配,直至找到合适的匹配或确定无法匹配。

python示例
def isMatch(s: str, p: str) -> bool:
    s_idx, p_idx = 0, 0  # Pointers for string and pattern
    last_star = -1       # Last position of '*' in p
    match_idx = 0        # Last position matched in s after a '*'
    while s_idx < len(s):
        if p_idx < len(p) and (p[p_idx] == '?' or p[p_idx] == s[s_idx]):
            s_idx += 1
            p_idx += 1
        elif p_idx < len(p) and p[p_idx] == '*':
            last_star = p_idx
            match_idx = s_idx
            p_idx += 1
        elif last_star != -1:
            p_idx = last_star + 1
            match_idx += 1
            s_idx = match_idx
        else:
            return False
    
    # Check for remaining characters in p
    while p_idx < len(p) and p[p_idx] == '*':
        p_idx += 1
    
    return p_idx == len(p)
# 示例调用
print(isMatch("adceb", "*a*b"))  # 输出: True
print(isMatch("acdcb", "a*c?b")) # 输出: False
算法分析
  • 时间复杂度:(O(M + N)),主要时间消耗在初次遍历和处理 ‘*’ 后的回溯上。
  • 空间复杂度:(O(1)),不需要额外的存储空间,所有操作均在原字符串上进行。

这三种方法各有优势和适用场景。动态规划提供了一种稳定的解决方案,适合大多数情况;双指针方法在空间上更优,适用于内存敏感的环境;而贪心算法尝试在运行时优化性能,特别适合需要频繁处理复杂模式的应用。选择哪种方法取决于具体的应用需求、性能考量和开发资源。


欢迎关注微信公众号 数据分析螺丝钉

相关文章
|
4月前
|
搜索推荐 索引 Python
【Leetcode刷题Python】牛客. 数组中未出现的最小正整数
本文介绍了牛客网题目"数组中未出现的最小正整数"的解法,提供了一种满足O(n)时间复杂度和O(1)空间复杂度要求的原地排序算法,并给出了Python实现代码。
125 2
|
2月前
|
程序员 C语言
【C语言】LeetCode(力扣)上经典题目
【C语言】LeetCode(力扣)上经典题目
|
2月前
|
Java C++ Python
【面试宝典】深入Python高级:直戳痛点的题目演示(下)
【面试宝典】深入Python高级:直戳痛点的题目演示(下)
|
2月前
|
设计模式 Unix Python
【面试宝典】深入Python高级:直戳痛点的题目演示(上)
【面试宝典】深入Python高级:直戳痛点的题目演示(上)
|
3月前
|
SQL Oracle 关系型数据库
CASE WHEN 语句的语法及示例,LeetCode 题目 “确认率” 练习
本文介绍了SQL中CASE语句的两种形式和语法,并通过LeetCode题目“确认率”的SQL查询示例展示了CASE语句在实际问题中的应用,解释了如何使用CASE语句计算特定条件的比率。
|
4月前
|
算法
LeetCode第12题目整数转罗马数字
该文章介绍了 LeetCode 第 12 题整数转罗马数字的解法,通过使用 TreeMap 按照整数从大到小排序,先使用大的罗马数字表示整数,再用小的,核心是先表示完大的罗马数字,想通此点该题较简单。
LeetCode第12题目整数转罗马数字
|
4月前
|
算法 Java
LeetCode经典算法题:矩阵中省份数量经典题目+三角形最大周长java多种解法详解
LeetCode经典算法题:矩阵中省份数量经典题目+三角形最大周长java多种解法详解
57 6
|
4月前
|
算法 Python
【Leetcode刷题Python】 LeetCode 2038. 如果相邻两个颜色均相同则删除当前颜色
本文介绍了LeetCode 2038题的解法,题目要求在一个由'A'和'B'组成的字符串中,按照特定规则轮流删除颜色片段,判断Alice是否能够获胜,并提供了Python的实现代码。
58 3
|
4月前
|
Python
【Leetcode刷题Python】50. Pow(x, n)
本文介绍了LeetCode第50题"Pow(x, n)"的解法,题目要求实现计算x的n次幂的函数,文章提供了递归分治法的详细解析和Python实现代码。
30 1