正規表示式匹配是真真的經典筆試、面試題了,這傢伙的動態規劃狀態轉移的細節得扣的仔仔細細,不然就是漏洞百出,著實細節魔鬼。當然本身的動態思路也是屬於比較困難的。很早之前做過的這題,再次覆盤發現還是會出問題。還是需要整理整理思路。
力扣10.正規表示式匹配
關於題幹就不在詳述了,可以直接參考力扣原題。感謝力扣。
所謂字串匹配,本質上就是驗證兩個串是否相同,初步的,相信判斷兩個字串是否相同,大家都知道怎麼處理。正規表示式則是在基礎上,新增了一些具有特殊功能的字元。在本題中,設模板串為s,待測串為p。
'.'可以替代任何字母
'*'可以重複其前乙個字母0~任意次數
根據子串行、子串一類的經驗,可以想到,動態規劃的狀態必然有兩種,即模板串的長度和待檢查串的長度。子問題即更短的串的匹配。
狀態有兩個,顯然是二維dp,定義dp陣列含義如下:
dp[i]
[j]表示s中前i個字元與p中前j個字元的匹配情況
選擇,即在模板串長度一定時,考慮p串第j個字元的匹配情況。分為三類
p[j]為字母
p[j]
==『.』
p[j]
=='*'
其中,根據題意,'.'
可以匹配任何字元,即可讓其等於s[i]
。因此,合併前兩種情況如下:
若s[i]
==p[j] 或 p[j]
=='.'時
dp[i]
[j]=dp[i-1]
[j-1];
//兩者均向前移動乙個狀態進行轉移
否則,無法匹配
第三種情況略顯複雜,出現'*'
時,我們需要考慮到底讓之前的那個字元重複幾次?從直觀的想法來看,我們可以列舉所有可能重複的次數,來判斷當前的匹配是否成功。下面來舉例子。
當重複0次
前乙個字元在匹配中不出現
即p[j]和p[j-
1]是否出現沒有區別,把它倆扔開不管
dp[i]
[j]=dp[i]
[j-2];
//因此從j-2
當重複1次
前乙個字元在匹配**現1次
即p[j-
1]存在
if(s[i]
==p[j-1]
) dp[i]
[j]=dp[i-1]
[j-2
]
當重複3次
前乙個字元在匹配**現2次
即p[j-
1]存在2次
if(s[i]
==p[j-1]
==s[i-1]
) dp[i]
[j]=dp[i-2]
[j-2
]
…
即重複幾次,需要在s中向前匹配幾個相同的字元。這就是所謂的列舉。但是這樣一來會大大增加時間複雜度,並不理想。
實際上,列舉的過程就是向前看s中是否存在當前字元的重複段,實際上,在之前的狀態轉移中,這些檢查已經完成了。因此,本質上只需要考慮當前字元出現與否。
若出現了,假設s[i]==s[i-1]
,dp[i][j]相當於在dp[i-1][j]
上進行了轉移,將p[j]多重複出現了一次。再者,如果沒有出現,就是0次重複的狀態。因此,此時的轉移方程為
dp[i]
[j]=dp[i-1]
[j] | dp[i]
[j-2
];
綜上,整體的狀態轉移如下,注意字串的索引越界問題。
if
(p[j-1]
=='*'
)else
考慮base case就是,兩個空串匹配成功。
貼上完整**
class
solution
public
:bool
ismatch
(string s, string p)
else}}
return dp[m]
[n];}}
;
正規表示式匹配 動態規劃專題
二 題目解析 3.遞迴 給定乙個字串 s 和乙個字元模式 p 實現支援.和 的正規表示式匹配。匹配應該覆蓋整個字串 s 而不是部分字串。輸入 s aa p a 輸出 false 解釋 a 無法匹配 aa 整個字串。輸入 s aa p a 輸出 true 解釋 代表可匹配零個或多個前面的元素,即可以匹...
LeetCode 正規表示式匹配(動態規劃)
難度 困難 給你乙個字串s和乙個字元規律p,請你來實現乙個支援 和 的正規表示式匹配。所謂匹配,是要涵蓋整個字串s的,而不是部分字串。示例1 輸入 s aa p a 輸出 false 解釋 a 無法匹配 aa 整個字串。示例2 輸入 s aab p c a b 輸出 true 解釋 因為 表示零個或...
正規表示式 匹配
字串 void abtr quint32 ab 表示乙個正規表示式 template class bidirectionaliterator class allocator std allocator sub match bidirectionaliterator class match resul...