1. 程式人生 > >LeetCode 10 正則表示式匹配

LeetCode 10 正則表示式匹配

基本思想,逐個字元匹配,檢視對應位置的字元是否相等,或者刪除前一個字元後檢視是否相等,或者重複前面字元(指的是上一個位置的字元,而不是所有前面的字元中的任意一個)若干次後檢視是否相等。為了方便分析,首先我們要對兩個字串的型別進行分類,字串S是指只包含字母的普通字串,字串P指的是包含‘.’和‘*’的模式字串。這兩個字串出現的情形可以分為以下四種。

1)兩個字串都為空,那麼不用匹配了,兩者是完全相等的,返回true。

2)如果字串S不為空,字串P為空,則字串P不可能去匹配S。那S為空,P不為空呢,這個時候是有可能去匹配的,因為P中的字元可以增加或減少(當然是在有字元‘*’的情況下),所以是有可能的。也就是說S不為空,P為空就返回false,其他情況再論。

3)我們注意到字元‘*’很重要,可以增加或刪除字元,因此在匹配的過程中可以以P中下一個要匹配的字元是否是‘*’來分。這裡首先講不是‘*’的情況。判斷對應位置字元是否相等,或者如果不相等時P中的字元是否是‘.’(別忘了‘.’可以表示任意一個字元),如果字元對應相等或者P中字元是’.‘,則進行下一位判斷(遞迴,S和P同步進行下一步),否則返回false。

4)這種情況當然就是P中當前匹配的字元的下一個字元是’*‘了。和3)一樣,判斷對應位置字元是否相等,或者如果不相等時P中的字元是否是‘.’,如果字元對應相等或者P中字元是’.‘,(這個時候要直接同步進入到下一位嗎,不行啊,既然P中的字元下一個是’*‘,則下一個位置對應位字元肯定不相等),此時就要看P中的’*‘匹配幾個前面的字元了,如果匹配0個,也就是說把前面的那個字元(即當前的字元)刪除,’*‘的已經做了他的工作了,則P中的字元要往前跳2位(例如S為aba,P為ab*ba),而S中的字元位置不變。如果匹配一個以上呢,也就說,P中的字元’*‘至少可以充當一個字元,即在*前可以新增一個字元,需要新增嗎,不需要,因為我們比較的是字元,虛擬新增的那個字元和當前P中的字元是一樣的,所以我們只需要把S中的字元往前前進一步,P中的位置保持不變(但是效果和真的新增後P中的字元往前一步一樣,)開始下一步的匹配,有人說這有可能匹配很多個字元後S到末尾了,而P還是’*‘,別往了’*‘有刪除作用啊,可以直接跳過’*‘。  好了,這是當前字元可以匹配的情況(例如S為abbba,P為abxa)。當前字元如果不匹配呢,那就簡單了,直接用’*‘把P中當前字元前面那個和S中不一樣的字元刪除,也就是說,S位置保持不變,P跳兩步(例如S為acab,P為abxcab)。有人說為什麼沒有S跳一步,P保持不變這種情形呢,當前已經不相等了,S中跳一步預設S當前的字元是可以匹配的,這是錯誤的。

程式碼如下:

class Solution {
public:
    bool isMatch(string s, string p) {
        
       return match(s,p,0,0);
    }
    bool match(string& s,string& p,int is,int ip)
    {
        if(is==s.size()&&ip==p.size()){
            return true;
        }else if(is!=s.size()&&ip==p.size()){
            return false;
        }else{
            if(ip+1==p.size()||p[ip+1]!='*'){
                if(is!=s.size()&&(s[is]==p[ip]||p[ip]=='.')){
                    return match(s,p,is+1,ip+1);
                }else{
                    return false;
                }
            }else {
                 if(is!=s.size()&&(s[is]==p[ip]||p[ip]=='.')){
                    return match(s,p,is,ip+2)|| match(s,p,is+1,ip);   
                }else{
                     return match(s,p,is,ip+2);
                 }
           }
       }
    }
};