[LeetCode]44. Wildcard Matching 深入浅出讲解和代码示例

来源:互联网 发布:linux mysql开机自启 编辑:程序博客网 时间:2024/05/29 17:19

1、汇总概要

本题是模式匹配问题,解题思路涵盖了递归、以及匹配算法的知识点

2、题目

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") ? falseisMatch("aa","aa") ? trueisMatch("aaa","aa") ? falseisMatch("aa", "*") ? trueisMatch("aa", "a*") ? trueisMatch("ab", "?*") ? trueisMatch("aab", "c*a*b") ? false

3、审题

该题是模式匹配问题。

4、解题思路


1、原串(s)和模式串(p)匹配规则考虑时,涉及到三种基本情况,以及其任意组合:

1) 模式串当前是字符时(p[j]是char):相等则继续比较下一个,不相等则返回不匹配(false)
2) p[j] == ‘?’时:当做相等,继续比较下一个;
3) p[j] == '*'时:跳过*,s中当前位置查看是否有与p[j+1]匹配的元素,这种情况较复杂。

以s='abcdefga', p='ab?*g*'为例,示意图讲解如下:



Step1:初始i=0, j=0,顺序比较s[i]和p[j], 相同时指针指向下一个,继续比较;不等时,返回false;
Step2:p[j] == '?'时,任意字符与其匹配,指针指向下一个继续比较;
Step3:p[j] == '*'时(j=3),跳过*,比较*的下一个字符p[4](即'g'),从s[3]开始,查找后面的字符是否有'g'(p[6]),
     1)若能找到, 则从其位置开始,继续循环执行Step1~Step3;
     2)若找不到,返回false;

以上是基本思路,确定比较规则后,代码中循环遍历即可。

2、还有一种较复杂的情况需考虑,在Step3中比较*后面的字符时,如果匹配到多个,应该以哪个为准?这种情况容易被忽略。

举例:
1)当s='abab', p='*abab'时:
'*'后面的'a'在s中多个位置都可以找到(i=0,i=2)那么应该以哪个位置为准呢:
以i=0为准(即从i=0的下一个位置开始,继续下一个比较),结果是true;
以i=2为准,结果是false;
结论:本例中应该以第一次匹配到的位置为准,即i=0;
2)s='abab', p='*ab'时,以1)例中同样的方式分析,应该以最后一次匹配到的位置为准,即i=2;
所以,这里有个动态规划的思路,在处理时,并不能确定应该是以第一次匹配到的位置为准,还是最后一次,或者是中间的某一次匹配到的位置。
妥善的处理方法是,遍历所有s串中可以匹配到*下一个字符的位置,止到结果是true。
[当存在多个*时,仍然用这种思路处理]

动态规划的常用实现方法是递归函数(实现代码见下)。

5、代码示例 - Java
public class WildcardMatching {public boolean subMatch(String s, String p,int iStart,int jStart) throws InterruptedException{int i = iStart;int j = jStart;int lens = s.length();int lenp = p.length();System.out.println("\n\nrecursion ====== "+lens+" "+lenp);boolean res = false;while(j<lenp && i<lens){System.out.println("\ngo loop--i,j: "+i+" "+j);//Thread.currentThread().sleep(1000);if(p.charAt(j)=='*'){/*get its next char * if next is *, skip => j++, and break;(no need to recursion) * if next is ? =>  i++(start index skep 1),j++; */if(j<lenp-1){//have next onej++;if(p.charAt(j)=='*'){//next is *j++;continue; //go to loop again}else if(p.charAt(j)=='?'){ //next is ?i++;j++;if(i>=lens-1){//? match the last one in swhile(j<lenp && p.charAt(j)=='*'){//one/multiple * after ?j++;}if(j>=lenp){res = true;return res;}}continue; //go to loop again}else{//go to recursion branchwhile(i<lens){while(i<lens && p.charAt(j)!=s.charAt(i)){if(p.charAt(j)=='?'){break;}i++;}/*if exist multiple i met,need to save all * 1)s=abab,p=*abab,i should choose 0 * 2)s=abab,p=*ab,i should choose 2 */res = subMatch(s,p,i,j);i++;if(res == true){return res;}//else, do recursion}continue;}}else{ //j>= lenp; one/multiple * in the tail of pres = true;return res;}} //end if(*)if(i<lens-1 && j==lenp-1){ //p get the endif(p.charAt(j)=='*'){res = true;}else{res = false;}return res;}else if(i==lens-1 && j<lenp-1){//s get the endwhile(j<lenp && (p.charAt(j)=='*' || p.charAt(j)==s.charAt(i) || p.charAt(j)=='?') ){j++;}if(j>=lenp-1){res = true;}else{res = false;}break;}else if(i==lens-1 && j==lenp-1){//both get the endif(s.charAt(i)==p.charAt(j) || p.charAt(j) == '?'){res = true;return res;}}if(s.charAt(i)==p.charAt(j)||p.charAt(j)=='?'){ //loop to comparei++;j++;}else{res = false;break;}}return res;}public boolean isMatch(String s, String p) throws InterruptedException{boolean res = subMatch(s,p,0,0);return res;}public static void main(String[] args) throws InterruptedException{//String s = "abcdefga";//String p = "ab?*g*a";//String s = "abcdefga";//String p = "ab?*g*";//String s = "aaaba";//String p = "a*?a*b*a";//String p = "aaa***ba";//String s = "abab";//String p = "*?*ba*?*";//String p = "***ab***";//String s = "abc12abc1d1dabc1d1e";//String p = "*abc?d?*e";String s = "abab1";String p = "*?*ba*??*";//String s = "ab";//String p = "??";WildcardMatching wm = new WildcardMatching();System.out.println(s+"\n"+p+"\n");boolean res = wm.isMatch(s,p);System.out.println("\nres: "+res);}}

注:可参考main中的s、p的赋值做单元测试;


---------------------------------------------------------------------------------------------------

本文链接:http://blog.csdn.NET/karen0310/article/details/75053593

请尊重作者的劳动成果,转载请注明出处!

---------------------------------------------------------------------------------------------------