• 正则表达式匹配与自动机


    自动机的核心就是“状态”和“状态转移”,所以自动机又叫状态机。而动态规划也恰好是“状态”与”状态转移“。自动机又分为DFA与NFA,DFA一个输入对应一个状态转移,转移过程是确定的,而NFA一个状态输入对应多个转移方程

    在LeetCode正则表达式匹配这道困难题目中,很明显*号对应着一个NFA,初始的状态为*号前面的字符,输入状态为*号,状态的转移分为匹配该字符零次和匹配该字符n次(n>=1)时text和pattern的移动位置,把匹配零次等同于状态机中的跳空,初始状态及该状态跳空即匹配零次的集合还能再接受pattern(i) == text(j)或者pattern(i)==.的输入,即

     子集A为匹配零次即置空的状态,该子集接受两个输入称为a和b,得到子集B和子集C,再以此由B和C继续接受输入,依次循环。

    而当*号匹配当前字符n次时,也同样可以抽象出一个DFA的初始状态,即当前字符相等时,进入text(i+1)&&pattern(j)的状态,接下来步骤跟匹配零次差不多。

    最后合并*号所有的情况就是,该匹配算法是个接受三个初始状态的nfa,当前pattern(i)==text(j)||pattern(i)==.,即算法中的first_match变量,该变量的两个状态再加上第二位是否有*号的状态判断,可知总共有三个初始状态

    所以该nfa转为dfa,该dfa的初态就要包含这三个状态,终态和nfa一样,都即pattern和text同时为空时。

    下面为递归代码,可以说模拟了nfa的匹配过程

    public boolean isMatch(String text, String pattern) {
            //递归回溯结束点
            if (pattern.isEmpty()) {
                return text.isEmpty();
            }
            boolean first_match = (!text.isEmpty() &&
                    (pattern.charAt(0) == text.charAt(0) || pattern.charAt(0) == '.'));
    
            //如果pattern长度大于2并且第二位是*,这一步isMatch3(text, pattern.substring(2)可以判定用到*匹配零个前字符isMatch3(text, pattern.substring(2)
            if (pattern.length() >= 2 && pattern.charAt(1) == '*') {
                //这个匹配判定用到*匹配零个前字符
                return (isMatch3(text, pattern.substring(2)) ||
                        //这个匹配判定*代表n个字符
                        (first_match && isMatch3(text.substring(1), pattern)));
            } else {
                //判定第二位不是*的情况都移位判定,每回递归只判断第一位,直到空
                return first_match && isMatch3(text.substring(1), pattern.substring(1));
            }
        }
    

      下面是动态规划解法

    class Solution {
        public boolean isMatch(String s, String p) {
            int ls = s.length(), lp = p.length();
            boolean[][] dp = new boolean[ls + 1][lp + 1];
            dp[0][0] = true;
            for(int j = 2; j <= lp; j++)
                dp[0][j] = dp[0][j - 2] && p.charAt(j - 1) == '*';
            for(int i = 1; i <= ls; i++) {
                for(int j = 1; j <= lp; j++) {
                    int m = i - 1, n = j - 1;
                    if(p.charAt(n) == '*')
                        dp[i][j] = dp[i][j - 2] || dp[i - 1][j] && 
                            (s.charAt(m) == p.charAt(n - 1) || p.charAt(n - 1) == '.');
                    else if(s.charAt(m) == p.charAt(n) || p.charAt(n) == '.') 
                        dp[i][j] = dp[i - 1][j - 1];
                }
            }
            return dp[ls][lp];
        }
    }
  • 相关阅读:
    【刷题】LOJ 6009 「网络流 24 题」软件补丁
    lab 项目
    js内的时间戳指的是当前时间到1970年1月1日00:00:00 UTC对应的毫秒数,和 unix时间戳是对应的秒数,差了1000倍
    js 原生: 身份证脱敏、唯一随机字符串uuid、对于高 index 元素的隐藏与显示
    diy 滚动条 样式 ---- 核心代码
    PC_后台管理系统
    三端兼容项目
    阿里小程序
    到位App_jQuery_art-template
    一步一步 copy163: 网易严选 ---- vue-cli
  • 原文地址:https://www.cnblogs.com/moonyaoo/p/12834067.html
Copyright © 2020-2023  润新知