正則表達式匹配與自動機


自動機的核心就是“狀態”和“狀態轉移”,所以自動機又叫狀態機。而動態規划也恰好是“狀態”與”狀態轉移“。自動機又分為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];
    }
}

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM