1. 程式人生 > >Leetcode:Regular Expression Matching

Leetcode:Regular Expression Matching

正則表達 ++ -- 進行 不能 所有 結果 stack class

題目大意是要求我們實現一個簡單的正則表達式全匹配判斷。其中正則表達式中只包含一般字符,以及全匹配字符.和變長字符*。其中.可以匹配一個字符,而*與前一個字符相關聯,x*可以被看作任意多個x(0到正無窮個)。題目要求我們判斷一個字符串是否與正則表達式完全匹配,比如‘.*‘完全匹配‘‘,但是‘a*‘不能完全匹配‘b‘。


這道題目可以用動態規劃來解決。記s為待匹配的字符串,n為s的長度,p表示正則表達式字符串,m為p的長度。我們先對p進行一些預處理,將p轉換為一般字符串(不包含.和*),但是其中每個字符都擁有兩個布爾屬性,分別是matchall (是否能匹配所有字符)和flexible (是否可以改變長度)。這可以通過類似下面的方式快速實現:

stk = empty-stack

for(i = 0; i < p.length; i++)

  if(p[i] == ‘*‘)

    stk.top.flexible = true

  else

    stk.push(p[i])

    if(p[i] == ‘.‘)

      stk.top.matchall = true

p = stk.inner-array

令dp[i][j]表示p[i...]與s[j...]是否完全匹配。dp[i][j]為真,當且僅當下述至少一個條件得到滿足:

1.如果p[i].flexible是假,且p[i]能匹配s[j],且dp[i+1][j+1]為真。

2.如果p[i].flexible是真,且dp[i+1][j]為真。

3.如果p[i].flexible是真,且p[i]能匹配s[j],且dp[i][j+1]為真。

這三個條件的充分性非常容易驗證,下面僅說明必要性。在dp[i][j]為真的情況下,若p[i]不可擴展,則顯然p[i]與s[j]匹配,且p[i+1:m]與s[j+1:n]匹配,這與條件一符合。若p[i]可擴展,那麽可以依據p[i]匹配0個字符和多個字符區分,匹配零個字符時,p[i+1:m]與s[j:n]匹配,匹配至少一個字符時有p[i:m]與s[j+1:n]匹配,而者分別落於條件2和條件3中。

利用以上的論述書寫我們的代碼:

getDp(i, j)

  if(dp[i][j] has been initialized) //如果dp[i][j]已經被初始化過了

    return dp[i][j]

  //處理條件1

  if(p[i].flexible == false)

    dp[i][j] = (p[i].matchall || p[i] == s[j]) && getDp(i+1,j+1)

  //處理條件2和3

  else

    flag = getDp(i + 1, j) || ((p[i].matchall || p[i] == s[j]) && getDp(i, j+1))

  return dp[i][j]

而對於s與p是否最終完全匹配,只需要調用getDp(0, 0)即可得到結果。上述代碼中沒有處理越界的情況,可以在為dp分配空間時分配額外的邊界空間,並在首次調用getDp之前對邊界情況做判斷。

上述代碼的空間復雜度完全取決於dp的大小,故可以認為是O(mn),而由於每次對getDp(i,j)的調用,如果dp[i][j]以及被初始化過了,則費用為O(1),而完全初始化dp的費用為O(nm),因此可以認為getDp(0,0)的時間復雜度為O(mn)。


最後還是老規矩,給出實現代碼:

技術分享
 1 package cn.dalt.leetcode;
 2 
 3 /**
 4  * Created by dalt on 2017/6/13.
 5  */
 6 public class RegularExpressionMatching {
 7     byte[][] matchStatuses;
 8     String text;
 9     int tlen;
10     char[] patternBuf;
11     int plen;
12     int[] patternExtra;
13     final int FLEXIBLE = 1 << 0;
14     final int MATCH_ALL = 1 << 1;
15 
16     public boolean isMatch(String s, String p) {
17 
18 
19         //Precalculate all needed information
20         int starCount = 0;
21         for (int i = 0, iBound = p.length(); i < iBound; i++) {
22             if (p.charAt(i) == ‘*‘) {
23                 starCount++;
24             }
25         }
26         text = s;
27         int validPatternLength = p.length() - starCount;
28         patternBuf = new char[validPatternLength];
29         patternExtra = new int[validPatternLength];
30         int wpos = 0;
31         for (int i = 0, iBound = p.length(); i < iBound; i++, wpos++) {
32             char ch = p.charAt(i);
33             if (ch == ‘*‘) {
34                 wpos--;
35                 patternExtra[wpos] |= FLEXIBLE;
36             } else if (ch == ‘.‘) {
37                 patternExtra[wpos] |= MATCH_ALL;
38             } else {
39                 patternBuf[wpos] = ch;
40             }
41         }
42         tlen = s.length() + 1;
43         plen = validPatternLength + 1;
44         matchStatuses = new byte[plen][tlen];
45         matchStatuses[plen - 1][tlen - 1] = 1;
46         for (int i = 0, iBound = tlen - 1; i < iBound; i++) {
47             matchStatuses[validPatternLength][i] = -1;
48         }
49         for (int i = plen - 2; i >= 0; i--) {
50             matchStatuses[i][tlen - 1] = (byte) (matchStatuses[i + 1][tlen - 1] == 1 && (patternExtra[i] & FLEXIBLE) == FLEXIBLE ? 1 : -1);
51         }
52         return match(0, 0);
53     }
54 
55     public boolean match(int i, int j) {
56         if (matchStatuses[i][j] != 0) {
57             return matchStatuses[i][j] == 1;
58         }
59         boolean flag;
60         if ((patternExtra[i] & FLEXIBLE) == 0) {
61             flag =  ((patternExtra[i] & MATCH_ALL) == MATCH_ALL || patternBuf[i] == text.charAt(j)) && match(i + 1, j + 1);
62         } else {
63             boolean matchAllFlag = (patternExtra[i] & MATCH_ALL) == MATCH_ALL;
64             flag = match(i + 1, j);
65             if (!flag) {
66                 flag = (matchAllFlag || patternBuf[i] == text.charAt(j)) && match(i, j + 1);
67             }
68         }
69         matchStatuses[i][j] = (byte)(flag ? 1 : -1);
70         return flag;
71     }
72 }
View Code

Leetcode:Regular Expression Matching