[Leetcode] Wildcard matching 通配符匹配
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
这题和正则表达式匹配有点类似,' . '和本题中的' ? '一样,区别在于' * ',在正则表达式那题中,' * '可以表示之前字符的0个或多个;本题中,可以表示任意字符串。好吧,做了,第一次做的时候,没有完全搞懂,这次出问题了,又去网上找帮助了。本文章参考了peerlessbloom 、点缀星辰、Grandyang。
思路:当*s ==*p || *p=='? '时,对应的指针分别++即可;当遇到字符' * '时,该怎么办呢?是否像正则表达式那题中的思路把 *s和*(p+1)去比较了?若是这样的,说明没有理解清楚:题目中' * '可以表示任意字符串的含义,举个例子来说明s=" aacabacd "和 p=" a*acd ",这种情况下,若是按上题中的思想,则要返回false,但是本题这种情况确是匹配的。这题中,' * '和' acab '匹配了。这如何实现的了?我们先看*号匹配的几种情况(例子来自 点缀星辰的博客,这里只是结合自己的语言给出了):
1)*号匹配了串 s 中间指定点秩后所有的字符。这里*号匹配了“bcac”。
2)*号匹配部分串的情况。这里*号匹配了“bc”。这种情况就是字符串p中的*号之后的字符' a '和*号对应的S中的字符' b '去匹配,若不匹配,则比较s 中的下一个,直到匹配。
那是否所有的情况就结束了?如果是这样的,就和正则表达式的那种情况,很相似了,好吧,我当时就是这么想的,错了。还有其他的情况,如:
3)如下图1,刚开始,*号的下一个和*号对应的S中的字符' a '匹配,这意味着*号代表0个字符,直到' d '和 ' b '不匹配,那这种情况,怎么办了?是否返回false?这种情况显然不会返回false,因为,图中绿色的部分是匹配的,这也说明了一个问题,就是*号代表0个字符这种形式是不对了。那该如何?接下来应该如图2所示,p中字符a跟s中字符c 对比,不匹配,再跟s中字符b对比,直到在s中遇到字符a,即匹配,这样,p和s同时的比较下一个字符。若后面还有*号,能遍历到*号,说明*号之前都是匹配的,这样只要重复上述过程即可。
图1
图2
这就遇到一个问题了?当匹配了若干字符之后,才发现不匹配,如情况3),这时如何像上述过程那样,比较p中*号的下一位和s中*号对应的那位的下一位了?这时,我们采取的方法是,当遇到*号时,我们将使用两指针记录下此时的值,若在以后的对比中,遇到不匹配的情况,即可返回。当然,p中*号的位置是相对不变的(直到遇到下一*号),而s中用来的对比字符是在变化的。代码如下:
1 class Solution { 2 public: 3 bool isMatch(const char *s, const char *p) 4 { 5 const char *preS=NULL; //用来记录位置 6 const char *preP=NULL; 7 8 while(*s) 9 { 10 if(*p=='?' || *p==*s) 11 { 12 p++; 13 s++; 14 } 15 else if(*p=='*') 16 { 17 preS=s; 18 preP=p++; 19 } 20 else if(preP) //后面遇到不匹配的情况,则返回重新比较情况3) 21 { 22 p=preP+1; 23 s=++preS; 24 } 25 else 26 return false; 27 } 28 while(*p=='*') 29 p++; 30 return !*p; 31 } 32 };