返回

直击本质,正则表达式匹配算法精髓解读

闲谈

Leetcode算法刷题 10.正则表达式匹配

前言

今天做了一道动态规划题目,Leetcode上的正则表达式匹配,分享下题解。

题目连接:10. 正则表达式匹配

思路

本题一看就是一个动态规划,或者递归解法,不过递归就太耗时了。

整体思路如下:

  1. 首先将正则表达式转换成一个NFA(Nondeterministic Finite Automaton,非确定性有限自动机)。

  2. 然后将字符串转换成一个DFA(Deterministic Finite Automaton,确定性有限自动机)。

  3. 最后再用NFA和DFA进行匹配,就可以得到结果。

实现细节

1. 正则表达式转NFA

正则表达式转NFA的规则如下:

  • . 匹配任何字符。
  • * 匹配0个或多个前面的字符。
  • + 匹配1个或多个前面的字符。
  • ? 匹配0个或1个前面的字符。
  • [] 匹配方括号中的任意一个字符。
  • () 将括号内的正则表达式作为一个整体。

例如,正则表达式.ab*c可以转换成NFA如下:

        ε
      /   \
     /     \
    a       b
   / \     / \
  ε   ε   ε   c

2. 字符串转DFA

字符串转DFA的规则如下:

  • 将字符串的第一个字符作为DFA的起始状态。
  • 将字符串的最后一个字符作为DFA的终止状态。
  • 将字符串中间的每个字符作为DFA的一个状态。
  • 将每个状态的转移函数设置为:如果该状态的字符与下一个字符匹配,则转移到下一个状态;否则,转移到终止状态。

例如,字符串"abc"可以转换成DFA如下:

     a -> b -> c -> $

3. NFA和DFA匹配

NFA和DFA的匹配规则如下:

  • 如果NFA的起始状态和DFA的起始状态匹配,则将NFA的起始状态和DFA的起始状态都标记为已访问。
  • 如果NFA的某个状态和DFA的某个状态都标记为已访问,并且这两个状态的转移函数相同,则将这两个状态都标记为已访问。
  • 如果NFA的某个状态和DFA的某个状态都标记为已访问,并且这两个状态的转移函数不同,则将这两个状态都标记为未访问。
  • 如果NFA的所有状态都标记为已访问,则匹配成功;否则,匹配失败。

例如,NFA和DFA如下:

        ε
      /   \
     /     \
    a       b
   / \     / \
  ε   ε   ε   c
       \ /     \
        \       \
         b       $

字符串"abc"与NFA和DFA匹配的过程如下:

  • 将NFA的起始状态和DFA的起始状态都标记为已访问。
  • 将NFA的a状态和DFA的a状态都标记为已访问。
  • 将NFA的b状态和DFA的b状态都标记为已访问。
  • 将NFA的c状态和DFA的c状态都标记为已访问。
  • 将NFA的状态和DFA的状态都标记为已访问。

因此,NFA和DFA匹配成功。

结语

正则表达式匹配算法是一道经典的动态规划题目,也是Leetcode上的一道热门题目。掌握正则表达式匹配算法的精髓,可以帮助你解决更多类似的题目,提升你的算法能力。