leetcode 10. 正則表達式匹配
阿新 • • 發佈:2019-05-16
turn 包含 類型 src class nbsp 第一個字符 char* 分享圖片
這道題最初刷題連答案都看不懂,實在不是一道容易的題目。
補充兩個C++知識:
1)string對象的.c_str() 返回一個c語言字符串指針 即const char* p類型的指針;
2)c語言字符串的末尾為‘\0’可以用 *p==0 判斷是否到達末尾。
遞歸解法不斷的對當前情況和之後的情況進行判斷:
1)當前匹配字符串p為空,如果此時s為空則return true,s不為空則return false;
2)當前匹配字符串p不為空,那麽對當前p和s進行匹配(不考慮下一位是否有*),結果為match
2.1)下一位有*時,a和b都有可能有正確的解:
a)如果正解在a中,即當前字符串應該出現0次,那麽無論當前的match成功與否,return isMatch(s,p.substr(2));
b)如果正解再b中,即當前字符串至少出現1次,那麽當前至少應該匹配成功,並且還要遞歸求解isMatch(s.substr(1),p.substr(1)),即return match&&isMatch(s.substr(1),p.substr(2));
2.2 ) 下一位沒有*時,
a)如果當前匹配成功match==true,那麽匹配下一個字符,即 if(match) return isMatch(s.substr(1),p.substr(2));
b)如果當前匹配失敗match==false,那麽不用匹配直接return false;
C++ 代碼如下:
一)使用string對象不使用指針
class Solution { public: bool isMatch(string s, string p) { //情況1,加入p為空那麽只要s為空那麽得到true反之false if(p.empty()) return s.empty(); //計算當前對應字符的匹配first_match,p不為空,匹配當前第一個字符(不包含s為空而p為a*之類的情況,只探討是否字母直接匹配和.匹配)bool match=!s.empty()&&(s[0]==p[0] || p[0]==‘.‘); //情況2,p當前長度大於2,而且下一個字符是*(p.length()>=2 && p[1]==‘*‘) if(p.length()>=2 && p[1]==‘*‘){ // 2.1(*為0個的情況)當前對應位置字符不匹配即first_match==false,那麽p當前字母為0個時還有匹配可能,即s和p.substr(2) //或者當前字符能匹配first_match=true但不合適因此也需要為0個,即s和p.substr(2) // 2.2(*為1個以上的情況)當前對應字符匹配 first_match==true,而且正確答案就在此,那麽匹配s的下一個字符和當前p的字符(因為*代表任意多的情況 return isMatch(s,p.substr(2)) || match && isMatch(s.substr(1),p); }else{ //情況3,如果p只剩下1個,而這時 // 3.1 first_match==true,那麽去決議s.substr(1)和p.substr(1) // 3.2 first_match==false,那麽已經false,不用繼續了 if(match) return isMatch(s.substr(1),p.substr(1)); else return false; } } };
缺點:遞歸過程中,需要不斷的復制儲存子串,因此時間消耗較多,幾百ms
二)使用指針:
// 優化後遞歸的版本,通過傳遞指針省去不斷的復制和存儲 20ms class Solution { public: bool isMatch(string s, string p) { //string對象的.c_str()返回一個c字符串的指針,即const char * return isMatch(s.c_str(),p.c_str()); } bool isMatch(const char* s,const char* p){ //c字符串是以\0結尾的 if(*p==0) return *s==0; bool match=(*s!=0) && (*s==*p||*p==‘.‘); if(*(p+1)==‘*‘){ return isMatch(s,p+2)|| match&&isMatch(s+1,p); }else{ return match&&isMatch(s+1,p+1); } } };
缺點:使用指針,相對更容易出bug和難以理解
leetcode 10. 正則表達式匹配