日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

动态规划之正则表达式匹配字符串

發布時間:2025/3/15 编程问答 10 豆豆
生活随笔 收集整理的這篇文章主要介紹了 动态规划之正则表达式匹配字符串 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

解題框架:【README1】動態規劃之解題思路

文章目錄

  • 題目
  • 解題思路
  • 動態規劃
  • CODE

題目

LeetCode10:正則表達式匹配

解題思路

正則表達式的匹配規則我在這里就不多說了,相信大家都很清楚。
本題會給出兩個字符串s和p,p代表的是模式串,也就是帶有正則表達式的那個字符串,判斷p是否可以匹配字符串s

.號很好實現,遇到它直接匹配就可。難點就在于*,因為一旦出現 *號,它前面的字符可以出現1次,也可以出現n次,也可以不出現。比如.a*b就可以匹配zaaab

關于字符串的撇匹配,大家首先想到的肯定是兩個指針:i和j分別在s和p上移動,如果他們都能移動到各自的字符串末尾,則匹配成功,否則失敗


所以如果我們先不要考慮*,代碼就能很容易寫出來

bool isMatch(string s,string p) {int i,j=0;while(i<s.size() && j<p.size()){if(s[j]==s[j] || p[j]=='.'){i++;j++;}else return false;}return true; }

如果p[j+1]為通配符*,則考慮的情況較多,主要分為以下兩種

1:如果s[i]==p[j],那么

  • p[j]有可能匹配多個字符,比如當s="aaa",p="a*"時,就匹配了3次
  • p[j]也有可能匹配0個字符,比如當s="aa",p="a*aa",可以發現匹配了0次
  • 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次還是多次 。那么既然屬于動態規劃的題目,因此這個問題就需要用到咋們之前講到過的思想來解決了。

  • 狀態是什么?自然是i和j的位置
  • 選擇是什么?自然就是p[j],也即是*應該匹配幾個字符
  • 動態規劃

    根據以上描述,首先按照暴力解法思想,先定義一個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決定了程序何時退出,以及退出的結果是否正確。

  • 如果j==p.size(),也就是p串走完,那么此時如果i也等于s.size(),就表示匹配成功
  • 但是如果i=p.size(),是不能通過判斷是否j==p.size()的方式來判斷是否成功的。因為可能會出現s="a",p=“ab*c*”這種情況,可以發現雖然p沒有走完,但是它仍然是匹配的。
  • 所以我們的思路是,首先if(j==p.size()),那么就return i==s.size(),如果此時i還等于s.size(),一定成功。
    另一個重點就是i==size()時,去除掉一些干擾情況

  • 如果i==size(),那么對于p來說,其中的字符和*一定是成對出現的
  • 上面成對出現有一種非常奇葩的情況,就是通配符出現字母前,這樣是無法匹配的,因此要把這種情況給剔除掉
  • 判斷的代碼如下

    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);} };

    總結

    以上是生活随笔為你收集整理的动态规划之正则表达式匹配字符串的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。