动态规划之正则表达式匹配字符串
解題框架:【README1】動態規劃之解題思路
文章目錄
- 題目
- 解題思路
- 動態規劃
- CODE
題目
LeetCode10:正則表達式匹配
解題思路
正則表達式的匹配規則我在這里就不多說了,相信大家都很清楚。
本題會給出兩個字符串s和p,p代表的是模式串,也就是帶有正則表達式的那個字符串,判斷p是否可以匹配字符串s
.號很好實現,遇到它直接匹配就可。難點就在于*,因為一旦出現 *號,它前面的字符可以出現1次,也可以出現n次,也可以不出現。比如.a*b就可以匹配zaaab
關于字符串的撇匹配,大家首先想到的肯定是兩個指針:i和j分別在s和p上移動,如果他們都能移動到各自的字符串末尾,則匹配成功,否則失敗
所以如果我們先不要考慮*,代碼就能很容易寫出來
如果p[j+1]為通配符*,則考慮的情況較多,主要分為以下兩種
1:如果s[i]==p[j],那么
2:如果s[i]!=p[j],那么
- p[j]只能匹配0次,然后看p的下一個字符是否能和s[i]匹配。比如s="aa",p="b*aa"
于是我們可以寫出偽代碼如下
if(s[i]==p[j] || p[j]=='.') {if(j<p.size()-1 && p[j+1]=='*'){//有通配符*可以匹配0次或多次}else{//沒有通配符*只能匹配1次i++;j++;} } else {if(j<p.size()-1 && p[j+1]=='*'){//有通配符*可以,只能匹配0次}else{//沒有通配符直接失敗return false;} }代碼的思路很清晰了,看起來的確很簡單,那么為什么這道題難度還是hard呢?其實問題就在于*應該匹配0次還是多次 。那么既然屬于動態規劃的題目,因此這個問題就需要用到咋們之前講到過的思想來解決了。
動態規劃
根據以上描述,首先按照暴力解法思想,先定義一個dp函數,如下
bool dp(string& s,int i,string& p,int j)如果該函數返回值為true,表示可以匹配,反之不可以
bool isMathch(string s,string p) {return dp(s,0,p,0); }bool dp(string& s,int i,string& p,int j) {if(s[i]==p[j] || p[j]=='.'){if(j<p.size()-1 && p[j+1]=='*'){//1:可以匹配0次,或者多次return dp(s,i,p,j+2) || dp(s,i+1,p,j);}else{//:2:只能匹配1次return dp(s,i+1,p,j+1);}}else{if(j<p.size()-1 && p[j+1]=='*'){//3:只能匹配0次,看下面有沒有相等的return dp(s,i,p,j+2);}else{//4:無法匹配return false;}} }上述代碼中,注釋中的解釋分別如下
1:可以匹配0次,或者多次:return dp(s,i,p,j+2) || dp(s,i+1,p,j)
j+2,i不變就是直接跳過p[j]和后面的通配符,即匹配了0次
i+1,j不變,就是p[j]已經匹配了s[i],但是p[j]還可以匹配s[i]后面的,也就是匹配多次
2:只能匹配1次:return dp(s,i+1,p,j+1),這種情況就不多做解釋了
3:只能匹配0次,看下面有沒有相等的:return dp(s,i,p,j+2)
- 這種情況和情況1中的第一種類似,也就是匹配0次
4:最后一種情況就是失敗
最后需要處理一個棘手的問題,就是base case,因為base case決定了程序何時退出,以及退出的結果是否正確。
所以我們的思路是,首先if(j==p.size()),那么就return i==s.size(),如果此時i還等于s.size(),一定成功。
另一個重點就是i==size()時,去除掉一些干擾情況
判斷的代碼如下
if(i==s.size()) {if(p.size()-j)%2!=0){return false;}for(;j<p.size();j+=2){if(p[j+1]!='*'){return false;}}return true; }CODE
至此我們就可以寫出完整的代碼了
class Solution { public:bool dp(string& s,int i,string& p,int j,unordered_map<string,bool>& memory){if(j==p.size())//如果p串匹配完了return i==s.size();//看s串的情況if(i==s.size()){if((p.size()-j)%2==1)//*和字符未成對出現return false;for(;j+1<p.size();j+=2)//防止出現x和x*y*z*的情況{if(p[j+1]!='*')return false;}return true;}//消除重疊問題string key=to_string(i)+","+to_string(j);if(memory.count(key))return memory[key];bool res=false;if(s[i]==p[j] || p[j]=='.'){if(j<p.size()-1 && p[j+1]=='*'){res=dp(s,i,p,j+2,memory) || dp(s,i+1,p,j,memory);}else{res=dp(s,i+1,p,j+1,memory);} }else{if(j<p.size()-1 && p[j+1]=='*'){res=dp(s,i,p,j+2,memory);}else{res=false;}}memory[key]=res;return res;}bool isMatch(string s, string p) {unordered_map<string,bool> memory;return dp(s,0,p,0,memory);} };總結
以上是生活随笔為你收集整理的动态规划之正则表达式匹配字符串的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Sprint第三阶段(第四天12.12)
- 下一篇: 琐碎