1. 程式人生 > >[劍指Offer] 19_正則表示式匹配

[劍指Offer] 19_正則表示式匹配

題目

請實現一個函式來匹配包含’.‘和’*‘的正則表示式。模式中的字元’.‘表示任意一個字元,而’*'表示它前面的字元可以出現任意次(含0次)。在本題中,匹配是指字串中的所有字元匹配整個模式。

例:

字串"aaa"與模式"a.a"和“ab*ac*a">匹配,但與"aa.a"和"ab*a"均不匹配。


思路

  1. 正面暴力深度優先搜尋。書上給出的解法。注意使用遞迴以便處理回溯。(a*a匹配aaa)
    約定:待匹配字串為 s ,匹配模式為 p 。
    當p超界時,判斷s是否已經全部匹配;
    當s超界時,判斷p是否已經全部匹配;若不是,剩下的p是否可以匹配空字串。
    當p == s 或者 p == .,過;
    當p+1 == *,判斷p == s
    不匹配,移動向匹配p+2。
    匹配, 1-【s繼續向下匹配p-1】,2-【此次s匹配下面移動向匹配p+2】,3-【此次不匹配s直接移動向下匹配p+2】(例如a*ab匹配ab,即使a*可以匹配a對於整個字串此時應當選擇跳過)。
    程式執行到這裡時,將會進行深度優先搜尋,試探上述三個情況,當遇見匹配a*a*a*a*a*b匹配aaaaac,時間複雜度將爆炸O(3^n)。然而這裡三個情況是有重疊的。下一個思路將會講解。

    1. 時間複雜度:O(3^n)
    2. 空間複雜度:O(n) 最深遞迴
  2. 從後暴力深度優先搜尋。因為*出現在字元後面,如果從前向後遍歷,將會需要判斷字元後一個是否為 * 。同時分析思路1,對於出現 * 時的策略,2-【此次s匹配下面移動向匹配p+2】,3-【此次不匹配s直接移動向下匹配p+2】,是同一種情況。因為當出現3時,即為選擇1->2策略。所以對於 * 根本上只有2種處理,1-【繼續匹配】2-【跳過】。
    此外,對於邊界書上的程式碼只考慮 s 是否超界時,p是否超界,對於p未超界情況,未分開討論,導致複雜度增加。

    1. 時間複雜度:O(2^n)
    2. 空間複雜度:O(n) 最深遞迴
  3. 一開始沒想到可以動態規劃,還是題目做的少了。在閱讀Github上的解法我才明白這道題和LCS問題是類似的。
    觀察模式能匹配時,必有模式的子模式匹配字串的子串。
    例如,aa*b 匹配 ab,必有aa*匹配a,必有 a 匹配 a。
    令字串 S = < s

    1 , s 2 , s 3 , . . . , s m > S = <s_1, s_2, s_3, ...,s_m> 模式 P = < p 1 , p 2 , p 3 , . . . , p n > P = <p_1, p_2, p_3, ...,p_n>
    假設 Z = < s 1 , s 2 , s 3 , . . . , s k > ( k < m ) Z = <s_1, s_2, s_3, ...,s_k>(k<m) 可以被模式 X = < p 1 , p 2 , p 3 , . . . , p i > ( i < n ) X = <p_1, p_2, p_3, ...,p_i>(i<n) 匹配
    1.如果 p i p_i 匹配 s k s_k ,則 < p 1 , . . . , p i 1 > <p_1,...,p_{i-1}> 匹配 < s 1 , s 2 , s 3 , . . . , s k 1 > <s_1, s_2, s_3, ...,s_{k-1}>
    2.如果 p i p_i 不匹配 s k s_k , 則 p i p_i 匹配 < > <空字元> < p 1 , . . . , p i 1 > <p_1,...,p_{i-1}> 匹配 < s 1 , s 2 , s 3 , . . . , s k > <s_1, s_2, s_3, ...,s_{k}>
    3.如果 < p 1 , . . . , p i 1 > <p_1,...,p_{i-1}> 不匹配 < s 1 , s 2 , s 3 , . . . , s k > <s_1, s_2, s_3, ...,s_{k}> ,則有 < p 1 , . . . , p i 1 > <p_1,...,p_{i-1}> 匹配 < s 1 , s 2 , s 3 , . . . , s k l > <s_1, s_2, s_3, ...,s_{k-l}> < p i > <p_i> 匹配 < s k l + 1 , s 2 , s 3 , . . . , s k >