1. 程式人生 > >Wildcard Matching:萬用字元匹配

Wildcard Matching:萬用字元匹配

Implement wildcard pattern matching with support for '?' and '*'.

'?' Matches any single character.
'*' Matches any sequence of characters (including the empty sequence).

The matching should cover the entire input string (not partial).

The function prototype should be:
bool isMatch(const char *s, const char *p)

Some examples:
isMatch("aa","a") → false
isMatch("aa","aa") → true
isMatch("aaa","aa") → false
isMatch("aa", "*") → true
isMatch("aa", "a*") → true
isMatch("ab", "?*") → true
isMatch("aab", "c*a*b") → false
思路:最大的難點在於:

ab|ef|cd|g|i|esc|de
ab|* |cd|?|i|*|de

這種匹配,即一個*不知道要匹配多少個字元,可能先匹配一個字元滿足要求,但是後來的匹配過程中發現無法繼續匹配時,需要回到*位置,匹配兩個字元,再繼續向前匹配,不斷重複,直到匹配完全或者發現不能匹配。因此,對於每個*位置,需要記錄下*的位置以及當時匹配的狀態情況(類似於遊戲中的復活點,可以saveloading)。

程式碼參考的Leetcode討論區的高票答案。

class Solution {
    public boolean isMatch(String s, String p) {
        int i = 0;//嘗試匹配 s
        int j = 0;//嘗試匹配 p
        int resurgence = -1;//匹配失敗時的復活點,即因為*的出現可能有多種長度的匹配,所以其中一種失敗後
        //p從“復活點”(上一個出現*的位置的狀態)重新匹配,而s在復活點處對應的字元則可以由*匹配,即更換成另一種長度的匹配
        
        int mark = 0;//記錄下匹配到*時s對應的位置,用於“復活”(用*將s的當前字串匹配掉)
        
        while(i<s.length()){
            if(j<p.length()&&(s.charAt(i)==p.charAt(j)||p.charAt(j)=='?')){//標準位置,均向前匹配
                i++;
                j++;
            }else if(j<p.length()&&p.charAt(j)=='*'){//記錄下復活點,用於處理由*帶來的長度不同的匹配時,可以回到之前匹配過的位置重新匹配
                resurgence = j;
                mark = i;
                j = resurgence + 1;
            }else if(resurgence!=-1){//當前匹配方式不可行,所以回到“復活位置”(前一*位置時的狀態),並用*匹配s在那一狀態下的字元
                //如:abefcdgiescdfimde與ab*cd?i*de匹配,正確切分是
                // ab|ef|cd|g|i|esc|de
                // ab|* |cd|?|i|*|de
                //但是可能匹配'f'時被切成:
                // ab|e|fcdgiescde
                // ab|*|cd?i*de
                //此時無法匹配,所以回到上一復活點(匹配*時的狀態),並用*匹配'f'
                // ab|ef|cdgiescde
                // ab|* |cd?i*de
                //就可以繼續匹配了
                j = resurgence + 1;
                i = mark + 1;
                mark++;
            }else{//p到達盡頭而s還有剩餘,或者就沒有復活點可以重新匹配
                return false;
            }
        }
        while(j<p.length()&&p.charAt(j)=='*') j++;//對於由若干個*組成的結尾,是可以匹配任意的字串,所以要排除掉指正情況
        return j==p.length();
    }
}