【leetcode】44. 通配符匹配(wildcard-matching)(BFS)[困難]

鏈接

https://leetcode-cn.com/problems/wildcard-matching/

耗時

解題:4.5 h
題解:36 min

題意

給定一個字符串(s)和一個字符模式(p) ,實現一個支持 ‘?’ 和 ‘*’ 的通配符匹配。

‘?’ 可以匹配任何單個字符。
‘*’ 可以匹配任意字符串(包括空字符串)。

兩個字符串完全匹配纔算匹配成功。

思路

以 p 爲行 s 爲列,構建一個 p.size() * s.size() 的矩陣,矩陣中 位置 (i,j) 表示:s[0:i] 和 p[0:j] 可以匹配,那麼問題將轉化爲是否可以從位置 (0,0) 走到 位置 (p.size()-1, s.size()-1)。
因爲字符串中 ** 與 * 的意義相同,並且還會對規則的實現造成影響,所以首先改造 p,將 p 中連續的多個 * 變爲一個。
尋路用的是 BFS,如果 p 的首字符 p[0] 爲 ‘?’ 或 ‘*’ 或者與 s[0] 相等,則將 (0,0) 入隊,然後開始 BFS。

  1. 如果當前位置的 p 字符爲 ‘*’,則可以向右走(即匹配對應 s 位置的字符)。如果這個 ‘*’ 是 p 第一個字符,並且 p 下面的字符爲 ‘?’ 或者與 s[0] 相等,那麼還可以向下走(即 ‘*’ 匹配空字符串)。
  2. 如果當前位置的下一個 p 字符爲 ‘*’,那麼可以直接向下走到達 ‘*’ 的位置(即 ‘*’ 匹配空字符串)。
  3. 當然如果當前位置 (i,j) 右下對應的 p[i+1] 爲 ‘?’ 或者與 s[j+1] 相等,則自然可以走到右下的位置。

還使用了記錄數組來記錄走過的位置,防止多次訪問同一個位置,優化運行時間。

時間複雜度:最壞情況下每個位置都要入隊,即 O(p.size()s.size())O(p.size() * s.size())

AC代碼

class Solution {
public:
    bool isMatch(string s, string p) {
        int p_num = p.size();
        int s_num = s.size();
        if((p_num == 0 || p == "*") && s_num == 0) return true;
        if((p_num == 0 && s_num != 0) || (p_num != 0 && s_num == 0)) return false;

        vector<vector<bool>> vis(p_num, vector<bool>(s_num, false));
        queue<pair<int, int>> q;
        
        string _p;
        for(int i = 0; i < p_num; ++i) {
            if(p[i] == '*' && !_p.empty() && _p.back() == '*') continue;
            _p += p[i];
        }
        p = _p;
        p_num = p.size();
        
        if(p[0] == '*' || p[0] == '?' || s[0] == p[0]) {
            q.push(make_pair(0, 0));
        } 
        while(!q.empty()) {
            pair<int, int> now = q.front();
            q.pop();
            if(vis[now.first][now.second]) continue;
            vis[now.first][now.second] = true;
            // goal
            if(now.first == p_num-1 && now.second == s_num-1) {
                return true;
            }
            // transfer
            if(p[now.first] == '*') {
                if(now.first == 0 && now.first+1 < p_num && (p[now.first+1] == '?' || p[now.first+1] == s[now.second])) {
                    q.push(make_pair(now.first+1, now.second));
                }
                if(now.second+1 < s_num) {
                    q.push(make_pair(now.first, now.second+1));
                }
            }
            if(now.first+1 < p_num && p[now.first+1] == '*') {
                q.push(make_pair(now.first+1, now.second));
            }
            if((now.first+1 < p_num && now.second+1 < s_num) && (p[now.first+1] == '?' || p[now.first+1] == s[now.second+1])) {
                q.push(make_pair(now.first+1, now.second+1));
            }
        }
        return false;
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章