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
实现通配符的功能。特殊的串匹配。这道题的迭代法会更加简单,运行速度更加快。还是相当有难度的题目。
参考了Leetcode上的程序,然后自己优化了一下。
下面是动态规划法的优化程序:
优化地方:增加一个bool tream标志。如果当前行全部为false,那么就可以判断最终结果也为false。如果字符串很长,又是不匹配的话可以加快很多速度。
这样可以让速度提高差不多100ms,有图:
原算法是300多ms,我修改之后就变为200多ms了。
修改:
vector
修正为
vector
参考程序:http://discuss.leetcode.com/questions/222/wildcard-matching
bool isMatch(const char *s, const char *p) {
if (!*s && !*p) return true;
int ms_max = 1;//size of *s
const char* ss = s;
while(*ss){ ++ms_max;++ss;}//ms_max = strlen(s)+1;
int np_max = 1;
const char* pp = p;
while(*pp){if(*pp!='*')++np_max;++pp;}//计算不带非*的字符长度+1
if(ms_max < np_max) return false;
//这里写vector(ms_max, false)居然Leetcode上AC了
//但是在vs上是下标溢出的,正确应该+1.
vector > r(2, vector(ms_max+1, false));
bool flag = 1;
r[0][0] = true;//最右上角初始化为true
do{//*p
//增加标志,提前判断匹配串,返回;当前行全部false,结果肯定false
bool tream = false;
int ms = 1;
ss = s;//每次从表的1的位置开始填表
if (*p == '*'){//3.
while(*p == '*') ++p;//处理掉重复的*
--p;//返回填表位置
//因为*可以和空""匹配,所有把当前行0列置真
r[flag][0] = r[!flag][0];//例如特殊情况:"aa", "*"
for( ;ms <= ms_max; ++ms){//up and left判断两格就可以了,没有所有格都判断
if (r[!flag][ms] || r[flag][ms-1])//这里没有从0开始
{
tream = true;
break;
}
else r[flag][ms] = false;
}
for(;ms <= ms_max; ++ms){
r[flag][ms] = true;
}
}
else{
do{//填写行
bool r_flag = false;//1.
if (*ss == *p || *p == '?'){//2.
r_flag = r[!flag][ms-1];//diagnal
}
r[flag][ms]=r_flag;
if (r_flag) tream = true;
++ms;++ss;
}while(*ss);//*s
r[flag][0] = false;//第二行开始的最右边格填false
}
if (tream == false) return false;
++p;
flag = !flag;//利用flag来交替使用两个数组代表一个二维表
}while(*p);
return r[!flag][ms_max-1];
}
下面是迭代程序,要熟悉这个思维:记录上一次开始比较的位置,如图:
下面程序是直接使用指针记录位置
bool isMatch(const char *s, const char *p) {
const char *backtrack_s = NULL, *backtrack_s = NULL;
while (*s) {
if (*p == '?' || *s == *p) {
++s;
++p;
}
else {
if (*p == '*') {
while (*p == '*')
++p;
if (*p == '\0')
return true;
backtrack_s = s;
backtrack_s = p;
}
else {//backtrack_s是为了判断是否到尾,注意:还有判断是否出现了*
if (backtrack_s) {
//注意:在当前位置往后判断出现不相等的时候,再重新回到下一个位置重新往后比较
s = ++backtrack_s;
p = backtrack_s;//恢复p的位置
}
//s的恢复位置backtrack_s已经试完,那么就不匹配
else return false;
}
}
}
while (*p == '*')//处理p末端的*
++p;
return (*s == '\0' && *p == '\0');
}
};
//2014-2-24 update AC
bool isMatch(const char *s, const char *p)
{
int sn = strlen(s);
int pn = strlen(p);
for (int i = 0, c = 0; i < pn; i++)
{
if (p[i] != '*') c++;
if (c > sn) return false;
}
vector > tbl(2, vector(sn+1));
tbl[0][0] = true;
bool idx = true;
bool finished = false;
for (int i = 0; i < pn && !finished; i++)
{
if (p[i] == '*')
{
while (i < pn && p[i] == '*') i++;
i--;
}
finished = true;
if (p[i] == '*')
{
int j = 0;
for (; j < sn && !tbl[!idx][j]; j++) tbl[idx][j] = false;
if (j <= sn) finished = false;
for (; j <= sn; j++) tbl[idx][j] = true;
}
else
{
tbl[idx][0] = false;
int j = 0;
for ( ; j < sn; j++)
{
if (s[j] == p[i] || p[i] == '?')
tbl[idx][j+1] = tbl[!idx][j];
else tbl[idx][j+1] = false;
if (tbl[idx][j+1]) finished = false;
}
}
idx = !idx;
}
return finished? false : tbl[!idx][sn];
}
本题关键的一个考点:判断p字符串中的总长字符减去*号数,得到的总长是否长于s字符串,如果长过,那么就返回假。