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
实现两个通配符?和*
?:可以匹配任意单一的字符
* :可以匹配任意长度的字符串(包括空串)
这个题其实有点像“编辑距离”的问题,可以根据两个字符串的长度mn(m=s.size();n=p.size()),划分成一个(n+1)*(m+1)的编辑矩阵record,也是看最后矩阵record[n][m]的值。
对于字符串s="bcd"与p="?ec"
初始化矩阵如下:
然后遍历矩阵
有以下三种情况
1. 如果s[i]==p[j] or p[j]=='?' 那么record[i+1][j+1]=record[i][j]
2. 如果p[j]=='*' 那么record[i+1][j+1]=record[i][j+1] || record[i+1][j]
3. s[i] != p[j] 那么record[i+1][j+1]=0;
最后矩阵长这样:
然后矩阵最后一项record[n][m]=0 所以不匹配
然后这次我们考虑通配符'*'
首先要考虑 '*' 在字符串首的情况,
'*' 可以匹配所有字符串,所以需要将record[1][0]置为1,根据上述情况2,可以将这一行都置为1
如果首个字符为'*'且后面还接有'*',那么record[i][0]均为1
考虑下面矩阵:s="bcd" p="**cd"
然后我们按照上面的规则,初始化矩阵
然后遍历矩阵,重复3种情况的判定,得到结果
代码如下:
class Solution {
public:
bool isMatch(string s, string p) {
int i = 0, j = 0, n = s.size(), m = p.size();
bool **record = new bool*[m + 1];
for (int u = 0; u < m + 1; u++)
{
record[u] = new bool[n + 1];
memset(record[u], 0, sizeof(bool)*(n+1));//设置初值为0
}
record[0][0] = true;
for (int i = 1; i <= m; i++)//初始化矩阵,对于存在'*'为字符串首的情况
record[i][0] = record[i - 1][0] && p[i - 1] == '*';
for (j = 0; j
从上面可以看出,如果是两个巨长的字符串,也许两个字符串从第一个字符比较就可以判定不匹配了,但是通过动态规划的方法我们进行了很多多余的计算,所以这里引入双指针的方法,对每个字符串引入一个指针进行比较判断。
· 引入2个指针 i , j 分别指向两个字符串的串首
· 引入2个指针ri , rj 分别记录字符串指针i , j 的状态
· 当 i 指向串尾 且 j 指向串尾时 返回 true,其余情况 false
同样判断4种情况
1. p[j]=='?' || s[i]==p[j] 那么 i++; j++
2. p[j]== '*' 那么 ri = i ; rj = j; j++;
3. rj > -1 那么 i = ++ri; j = rj +1;
4. 其余情况 return false;
到最后可能 j 并没有指向串尾,而是指向 '*',跳过冗余的'*' 如果 j 指向串尾那么return true 否则 return false;
对于 s="bcd" p="**cd" 相当于只进行了 以下箭头的计算,所以更加便捷
对于 s="bbb" p="**cd" :
class Solution {
public:
bool isMatch(string s, string p) {
int n = s.size(), m = p.size();
int i = 0, j = 0, ri = -1, rj = -1;
while (i < n)
{
if (p[j] == '*')
{
ri = i;
rj = j++;
}
else if (p[j] == '?' || p[j] == s[i])
{
i++; j++;
}
else if (rj > -1)
{
i = ++ri;
j = rj+1;
}
else return false;
}
while (j < m&&p[j] == '*')j++;
return j == m;
}
};
整体思路与上面双指针类似,只不过是通过递归的方式完成,runtime比思路1快比思路2慢。
class Solution {
int dfs(string& s, string& p, int si, int pi) {
if (si == s.size() and pi == p.size()) return 2;
if (si == s.size() and p[pi] != '*') return 0;
if (pi == p.size()) return 1;
if (p[pi] == '*') {
if (pi + 1 < p.size() and p[pi + 1] == '*')
return dfs(s, p, si, pi + 1); // skip duplicate '*'
for (int i = 0; i <= s.size() - si; ++i) {
int ret = dfs(s, p, si + i, pi + 1);
if (ret == 0 or ret == 2) return ret;
}
}
if (p[pi] == '?' or s[si] == p[pi])
return dfs(s, p, si + 1, pi + 1);
return 1;
}
public:
bool isMatch(string s, string p) {
return dfs(s, p, 0, 0) > 1;
}
};