题目链接:
https://leetcode-cn.com/problems/wildcard-matching/
难度:困难
44. 通配符匹配
给定一个字符串 (s) 和一个字符模式 (p) ,实现一个支持 '?' 和 '*' 的通配符匹配。
'?' 可以匹配任何单个字符。
'*' 可以匹配任意字符串(包括空字符串)。
两个字符串完全匹配才算匹配成功。
说明:
s 可能为空,且只包含从 a-z 的小写字母。
p 可能为空,且只包含从 a-z 的小写字母,以及字符 ? 和 *。
示例:
输入:
s = "aa"
p = "a"
输出: false
解释: "a" 无法匹配 "aa" 整个字符串。
示例:
输入:
s = "acdcb"
p = "a*c?b"
输出: false
不会! 好难。。。 只是勉强看懂的动态规划的方法 类似的题目之前遇到过 好像是第十题来着 也是动态规划 忘记了。。
虽然知道是动态规划方法 但是公式找错了
正确的转移方程:
s[i]==p[j] || p[j]=='?' dp[i][j]=dp[i-1][j-1]
p[j]=='*' dp[i][j]= dp[i-1][j]|| dp[i][j-1]
其他 false
还要考虑临界状态
1 当字符串 s 和模式 p 均为空 dp[0][0]=true
2 模式p为空 字符串非空 dp[i][0]=false
3 p 的前j个字符均为星号时,dp[0][j]=true
class Solution {
public:
bool isMatch(string s, string p) {
int m=s.size();
int n=p.size();
vector<vector<bool>> dp(m + 1, vector<bool>(n + 1));
dp[0][0]=true;
for (int i=1;i<n+1;i++){
if (p[i - 1] == '*') {
dp[0][i]=true;
}else{
break;
}
}
for (int i=1;i<=m;i++){
for (int j=1;j<=n;j++){
if (p[j-1]=='*'){
dp[i][j] = dp[i][j - 1] | dp[i - 1][j];
}else if(p[j-1]=='?'||p[j-1]==s[i-1]){
dp[i][j] = dp[i - 1][j - 1];
}
}
}
return dp[m][n];
}
};
以下两种方法没看懂 这道题好难啊 以后在看( 做个标记 设置为转载,什么时候看懂了在重新写一下,取消标记设为原创 。。。。)
贪心策略
class Solution {
public:
bool isMatch(string s, string p) {
auto allStars = [](const string& str, int left, int right) {
for (int i = left; i < right; ++i) {
if (str[i] != '*') {
return false;
}
}
return true;
};
auto charMatch = [](char u, char v) {
return u == v || v == '?';
};
while (s.size() && p.size() && p.back() != '*') {
if (charMatch(s.back(), p.back())) {
s.pop_back();
p.pop_back();
}
else {
return false;
}
}
if (p.empty()) {
return s.empty();
}
int sIndex = 0, pIndex = 0;
int sRecord = -1, pRecord = -1;
while (sIndex < s.size() && pIndex < p.size()) {
if (p[pIndex] == '*') {
++pIndex;
sRecord = sIndex;
pRecord = pIndex;
}
else if (charMatch(s[sIndex], p[pIndex])) {
++sIndex;
++pIndex;
}
else if (sRecord != -1 && sRecord + 1 < s.size()) {
++sRecord;
sIndex = sRecord;
pIndex = pRecord;
}
else {
return false;
}
}
return allStars(p, pIndex, p.size());
}
};
在leetcode评论区中无意中看到的,很强,但是我没看懂 记录
class Solution {
public:
bool isMatch(string s, string p) {
int i = 0, j = 0, iStar = -1, jStar = -1, m = s.size(), n = p.size();
while (i < m) {
if (j < n && (s[i] == p[j] || p[j] == '?')) {
++i, ++j;//i,j向后瞬移
} else if (j < n && p[j] == '*') {//记录如果之后序列匹配不成功时, i和j需要回溯到的位置
iStar = i;//记录星号
jStar = j++;//记录星号 并且j移到下一位 准备下个循环s[i]和p[j]的匹配
} else if (iStar >= 0) {//发现字符不匹配且没有星号出现 但是istar>0 说明可能是*匹配的字符数量不对 这时回溯
i = ++iStar;//i回溯到istar+1 因为上次从s串istar开始对*的尝试匹配已经被证明是不成功的(不然不会落入此分支) 所以需要从istar+1再开始试 同时inc istar 更新回溯位置
j = jStar + 1;//j回溯到jstar+1 重新使用p串*后的部分开始对s串istar(这个istar在上一行已经inc过了)位置及之后字符的匹配
} else return false;
}
while (j < n && p[j] == '*') ++j;//去除多余星号
return j == n;
}
};