用動(dòng)態(tài)規(guī)劃解決通配符匹配字符串問題

leetcode上這個(gè)題目出現(xiàn)了兩次,基本都是要求答題者寫代碼完成 '*' 和 '?' 通配符的匹配。
一下摘錄其中一題:

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

解決這道題可以用遞歸的方法,遞歸的思路代碼如下:
下列代碼中,首先判斷特殊情況(終止條件), 分兩種情況討論

  • 當(dāng)傳入的p為空時(shí)。
  • 當(dāng)傳入的s為空時(shí)。
    然后考慮一般情況,也分兩種情況討論:
  • p 開頭為 '*',若開頭為星號(hào),接下來有三種匹配方式:
    • p[0] 僅匹配單個(gè)字符 s[0],p[1] ~ p[m] 匹配 s[1] ~ s[n],此時(shí)遞歸調(diào)用 isMatch(s.substr(1,s.size() - 1), p.substr(1,p.size() - 1))
    • p[0] 匹配字符串 s[0] ~ s[i],此時(shí)遞歸調(diào)用isMatch(s.substr(1,s.size() - 1), p.substr(0,p.size() ))
    • p[0]匹配空字符串,此時(shí)遞歸調(diào)用isMatch(s.substr(0,s.size() ), p.substr(1,p.size() - 1))
  • p 開頭不為 '*',如果p[0] 與 s[0]匹配,此時(shí)遞歸調(diào)用 isMatch(s.substr(1,s.size() - 1), p.substr(1,p.size() - 1)),否則匹配失敗。
    將以上思路寫成代碼如下:
class Solution {
public:
    bool isMatch(string s, string p) {
        if(p.size() == 0) {
            if(s.size() == 0)
            return true;
            return false;
        }
        if(s.size() == 0) {
            if(p[0] == '*')
                return isMatch(s.substr(0,s.size()), p.substr(1,p.size() - 1));
            return false;
        }
        bool res;
        if(p[0] == '*') {
            res = isMatch(s.substr(1,s.size() - 1), p.substr(1,p.size() - 1)) || 
            isMatch(s.substr(1,s.size() - 1), p.substr(0,p.size())) || 
            isMatch(s.substr(0,s.size()), p.substr(1,p.size() - 1));
        }
        else {
            if(p[0] == s[0] || p[0] == '?')
                res = isMatch(s.substr(1,s.size() - 1), p.substr(1,p.size() - 1));
            else
                return false;
        }
        return res;
    }
};

但是,遞歸的思路解法速度不夠,再leetcode上會(huì)超時(shí),那么就需要我們用動(dòng)態(tài)規(guī)劃解決。
同樣的道理,根據(jù)上述遞歸的思路寫出遞推關(guān)系式

P[i][j] = P[i - 1][j - 1] && (s[i - 1] == p[j - 1] || p[j - 1] == '?'), if p[j - 1] != '*';
P[i][j] = P[i][j - 1] || P[i - 1][j], if p[j - 1] == '*'.

依據(jù)上述關(guān)系,可以寫出新的代碼,代碼如下:

class Solution {
public:
    bool isMatch(string s, string p) { 
        int m = s.length(), n = p.length();
        vector<bool> cur(m + 1, false); 
        cur[0] = true;
        for (int j = 1; j <= n; j++) {
            bool pre = cur[0]; // use the value before update
            cur[0] = cur[0] && p[j - 1] == '*'; 
            for (int i = 1; i <= m; i++) {
                bool temp = cur[i]; // record the value before update
                if (p[j - 1] != '*')
                    cur[i] = pre && (s[i - 1] == p[j - 1] || p[j - 1] == '?');
                else cur[i] = cur[i - 1] || cur[i];
                pre = temp;
            }
        }
        return cur[m]; 
    }
};
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容