鏈接
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。
- 如果當前位置的 p 字符爲 ‘*’,則可以向右走(即匹配對應 s 位置的字符)。如果這個 ‘*’ 是 p 第一個字符,並且 p 下面的字符爲 ‘?’ 或者與 s[0] 相等,那麼還可以向下走(即 ‘*’ 匹配空字符串)。
- 如果當前位置的下一個 p 字符爲 ‘*’,那麼可以直接向下走到達 ‘*’ 的位置(即 ‘*’ 匹配空字符串)。
- 當然如果當前位置 (i,j) 右下對應的 p[i+1] 爲 ‘?’ 或者與 s[j+1] 相等,則自然可以走到右下的位置。
還使用了記錄數組來記錄走過的位置,防止多次訪問同一個位置,優化運行時間。
時間複雜度:最壞情況下每個位置都要入隊,即
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;
}
};