Python LeetCode 10正则表达式

44 篇文章 0 订阅
24 篇文章 1 订阅

第一版:p的2各字符一组匹配,分析.,x状况

"""
10. 正则表达式匹配
给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 '.' 和 '*' 的正则表达式匹配。

'.' 匹配任意单个字符
'*' 匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。


示例 1:

输入:s = "aa" p = "a"
输出:false
解释:"a" 无法匹配 "aa" 整个字符串。
示例 2:

输入:s = "aa" p = "a*"
输出:true
解释:因为 '*' 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 'a'。因此,字符串 "aa" 可被视为 'a' 重复了一次。
示例 3:

输入:s = "ab" p = ".*"
输出:true
解释:".*" 表示可匹配零个或多个('*')任意字符('.')。
示例 4:

输入:s = "aab" p = "c*a*b"
输出:true
解释:因为 '*' 表示零个或多个,这里 'c' 为 0 个, 'a' 被重复一次。因此可以匹配字符串 "aab"。
示例 5:

输入:s = "mississippi" p = "mis*is*p*."
输出:false

"""
#踩了无数坑的正则表达式:1)合并同类a* a*;  否则一旦最终是匹配错误的会不停循环出无数组合(a*爆发而非收敛)
# #                    2)剩余长度:s=p=0成功; s=0,p!=0 看是否剩余了x*; 不剩余x*,或者s!=,p=0 (sp=0)全错
                      # 3)正式匹配: 字母+'*' (字母不能配上,字母能配上),.+'*', '.'开头,普通开头

class Solution:
    def isMatch(self, s: str, p: str) -> bool:
        if len(p) == 0 and len(s) == 0:
            return True  # 截止条件之一,同时匹配空掉了

        if len(p) == 1:
            # return True if s == p else False
            if p != '.':
                return True if s == p else False
            else:
                return True if len(s) == 1 else False

        if len(p) >= 2 and p[1] == '*' and len(s) == 0:
            return self.isMatch(s, p[2:])

        if len(p) * len(s) == 0:
            return False  # 两个只有1个为0,错误

        # 多个同类的 a*a*a*相当于1个
        if len(p) >= 4 and p[0] == p[2] and p[1] == '*' and p[3] == '*':
            return self.isMatch(s, p[2:])

        if s[0:2] == p[0:2]:  # 2个字符为单位进行递归,尽量每次去掉一个字符
            return self.isMatch(s[1:], p[1:])
        elif p[0] == '.' and p[1] == '*':  # 最强组合.*,匹配任意字符串(只要没有猪队友)
            return self.isMatch(s, p[2:]) or self.isMatch(s[1:], p[2:]) or self.isMatch(s[1:], p)
            # 匹配0个,1个,1+个
        elif p[0] == '.':
            print(s[0:], s[0] + p[1:])
            return self.isMatch(s[0:], s[0] + p[1:])  # 开头.,替换成s对应的字符
        elif s[0] != p[0] and p[1] == '*':
            return self.isMatch(s, p[2:])
        # elif s[0] == p[0] and p[1] == '.' and len(s) > 1:
        #     return self.isMatch(s[1:], s[1] + p[2:]) or self.isMatch(s[1:], p[1:]) #保留.用作.*结构的强匹配
        elif s[0] == p[0] and p[1] == '*':
            return self.isMatch(s, p[2:]) or self.isMatch(s[1:], p[2:]) or self.isMatch(s[1:], p)
            # 配0个,*匹配1个(原始a*对应a),匹配1+个(对应aa*)(+1个是可以反复递归的,一直递归到s中再没有匹配的p[0]为止)
            # self.isMatch(s[1:], p)
        elif s[0] == p[0]:  # 得过且过,过完这个,下一个也许会出现x*结构 #and s[1] != p[1]
            return self.isMatch(s[1:], p[1:])
        else:
            return False

第二版:只看p的第二个符号做分支选择

稍微改进:合并同类的逻辑判断:
class Solution:
    def isMatch(self, s: str, p: str) -> bool:
        if len(p)==0 and len(s) == 0:
            return True #截止条件之一,同时匹配空掉了
        
        if len(p) == 1:
            #return True if s == p else False
            if p != '.':
                return True if s == p else False
            else:
                return True if len(s) == 1 else False

        if len(s) == 0 and p[1] == '*':
            return self.isMatch(s, p[2:])

        if len(s) * len(p) == 0:
            print(1)
            return False

        #合并同类 x*,防止匹配膨胀,太过贪婪
        if len(p) > 3 and p[1] == '*' and p[0:2] == p[2:4]:
            return self.isMatch(s, p[2:])


        if p[1] == '*' and p[0] == '.':
            return self.isMatch(s, p[2:])  or self.isMatch(s[1:], p) # self.isMatch(s[1:], p[2:]) or /
        elif p[1] == '*' and p[0] == s[0]:
            return self.isMatch(s, p[2:]) or self.isMatch(s[1:], p)
        elif p[1] == '*' and p[0] != s[0]:
            return self.isMatch(s, p[2:])
        elif p[0] == '.':
            return self.isMatch(s[1:], p[1:])
        elif p[0] == s[0]:
            return self.isMatch(s[1:], p[1:])
        else:
            # print(2, s, p)
            return False

代码简化了,逻辑上复杂在预先判断剩余长度0、长度1的状况

第三版:大神版,利用len(s) p[0]in大为简化判断

  • 递归的很溜溜溜
  • 注意合并同类(a* a* a* a*)等,否者重复递归浪费大量循环试错
class Solution:
    def isMatch(self, s: str, p: str) -> bool:
        if len(p) == 0:
            #print(s, not s)
            return not s

        match = (len(s) > 0) and (p[0] in [s[0], '.'])

        if len(p) > 3 and p[1] == '*' and p[0:2] == p[2:4]: #合并同类的a*加速明显(避免多轮重复迭代)15504ms减少到88ms
            return self.isMatch(s, p[2:])

        if len(p) > 1 and p[1] == '*':
            #print(match, s, p, ' match ', s and (p[0] in [s[0], '.']))
            return self.isMatch(s, p[2:]) or (match and self.isMatch(s[1:], p))  #match and  配0并不一样要配上;

        #print(match)
        return match and self.isMatch(s[1:], p[1:])
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值