首页 > 其他分享 >10. 正则表达式匹配

10. 正则表达式匹配

时间:2022-11-08 20:01:11浏览次数:50  
标签:10 匹配 字符 正则表达式 range 难点 转移 dp

题目描述

给了一个字符串s和字符规律p
其中p可能含有"."和"","."可以匹配任何单个字符,""需要和前面字符结合,表示匹配0-任意个前面字符
问给定的p能不能匹配s

f1-序列dp

基本分析

1.怎么定义状态?dp[i][j]表示p的前j个字符能不能匹配s的前i个字符
2.对i分类还是对j分类?j有3种情况,对j分类

  • p[j]是字符,要能转移需要有dp[i-1][j-1]能匹配,s[i]=p[j]
  • p[j]是".", 要能转移需要有dp[i-1][j-1]能匹配,p[j]是'.'
  • p[j]是"*", 需要结合前面一个字符考虑,可能能匹配0个,1个,多个,这个可能是无限的,这个题的难点就在这里

3.怎么推导出来p[j]是"*"的表达式?

  • 枚举f[i][j]成立时匹配0、1、2、。。。k时的表达式
  • 将i替换为i-1,得到f[i-1][j]时候的表达式
  • 分析以上表达式关系,得到f[i][j] = f[i][j-2] 或 (f[i-1][j] 且 p[j-1]能匹配s[i])

4.定义状态的时候有啥细节?

  • 预处理:在原字符插空格,(1)为了能直接用i和j表达第几个;(2)可以把f[0][0]=True的结果滚下去
  • 开数组:开到[n+1][m+1]
  • f[0][0] = True

5.转移的时候的细节?

  • 遍历时候,对s是range(0, n+1),需要考虑匹配0;对p是(1,m+1)
  • p[j]的后面接"*"时,要一起考虑,需要pass
  • p[j]是字符或者"*"时,可以一起考虑,但因为有i-1的转移,需要判断i的越界情况
  • p[j]是"*"时,按照转移关系来,需要判断j的越界情况,i的越界情况,p[j-1]能匹配s[i]的情况

代码

class Solution:
    def isMatch(self, s: str, p: str) -> bool:
        n, m = len(s), len(p)
        # 头插空格的原因?
        s = ' ' + s
        p = ' ' + p

        f = [[False] * (m+1) for _ in range(n+1)]
        f[0][0] = True

        for i in range(n+1):
            for j in range(1, m+1):
                # 如果后面是*表示不能单独使用,跳过
                if j+1 <= m and p[j+1]=="*":
                    continue
                # 考虑为普通字符或者"."
                if  i-1 >=0 and p[j] !="*":
                    f[i][j] = f[i-1][j-1] and (s[i]==p[j] or p[j]==".")
                elif p[j] == "*":
                    f[i][j] = (j-2>=0 and f[i][j-2]) or (i-1>=0 and f[i-1][j] and (s[i]==p[j-1] or p[j-1]=="."))
        return f[n][m]

复杂度

时间:共计\(n \cdot m个状态, O(n \cdot m)\)
空间:\(O(n \cdot m)\)

总结

第1个难点是状态定义的写法,需要两个维度i和j,来表示前j匹配前i的情况
第2个难点在于考虑转移时对谁进行分类?这里是j,题目给了3个情况
第3个难点是具体考虑怎么转移?对p[j]取非"*"的时候,按照之前的定义,可以解决了,但是对于"*"的情况,可以匹配0、1、2、...n, 这样写or太长了,怎么处理?题目的做法是用了换元法,先写成[i][j]的情况,再写[i-1][j]的情况,然后发现可以把无限的式子化为有限
第4个难点是状态定义的细节,为了转移f[0][0],用了头插空格
第5个注意点是转移的时候,需要往前去翻,这个时候不管对i还是j,都要先保证不越界

标签:10,匹配,字符,正则表达式,range,难点,转移,dp
From: https://www.cnblogs.com/zk-icewall/p/16870976.html

相关文章

  • 10-注册中心&Zookeeper设计实践课_ev 没用
                                               ......
  • 20221107 24. Linux 核心编译与管理
    24.1编译前的任务:认识核心与取得核心源代码“核心(kernel)”是整个操作系统的最底层,他负责了整个硬件的驱动,以及提供各种系统所需的核心功能,包括防火墙机制、是否支持LVM......
  • 20221107 23. X Window 设置介绍
    在Linux上头的图形接口我们称之为XWindowSystem,简称为X或X11啰!为何称之为系统呢?这是因为X窗口系统又分为Xserver与Xclient,既然是Server/Client(主从架......
  • 10 个 JavaScript Promise 的面试题
    英文|https://betterprogramming.pub/10-javascript-promise-challenges-before-you-start-an-interview-c9af8d4144ec翻译|杨小爱Promise是JavaScript异步编程的关......
  • 20220810 06. Linux 文件与目录管理
    6.1目录与路径6.1.1相对路径与绝对路径路径(PATH)绝对路径:路径的写法“一定由根目录/写起”,例如:/usr/share/doc这个目录。相对路径:路径的写法“不是由/写起......
  • Python中10个常见的安全漏洞及修复方法
    编写安全的代码很困难,当你学习一门编程语言、一个模块或框架时,你会学习其使用方法。在考虑安全性时,你需要考虑如何避免代码被滥用,Python也不例外,即使在标准库中,也存在着许多......
  • 10 个重构代码时的最佳实践
    什么是重构?重构是在不改变其功能的情况下改进现有代码设计的过程。作为软件开发人员,我们不断面临改进和优化代码的需求。无论是为了性能、可读性还是可维护性,重构代码都是一......
  • 10 个CSS实现元素居中的方法汇总
    英文|https://javascript.plainenglish.io/10-css-tricks-you-should-know-for-centering-elements-61092d35b659翻译|杨小爱在前端开发工程师的日常生活中,使用CSS使......
  • 10个你每天都需要用到的Javascript代码片段
    英文|https://medium.com/dev-genius/10-useful-javascript-code-snippets-that-you-need-everyday-2de5c4ef79c6翻译|小爱程序员总是喜欢做一些新的事情,但是每个项目都......
  • SBT40100VFCT-ASEMI塑封肖特基二极管SBT40100VFCT
    编辑-ZSBT40100VFCT在ITO-220AB封装里采用的2个芯片,其尺寸都是120MIL,是一款塑封肖特基二极管。SBT40100VFCT的浪涌电流Ifsm为300A,漏电流(Ir)为10uA,其工作时耐温度范围为-65~......