首页 > 代码库 > Leetcode: Wildcard Matching

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

难度:90,这道题跟Edit Distance很像。Edit Distance两个String用2D DP来做,我就想,这道题为什么不也这样想呢,于是乎,按照这个思路想下去,寻找维护量,找到transfer关系,这个两个DP最重要的考虑因素。这道题也就豁然开朗了。以后这种两个String进行操作的题目,都可以往multidimensional DP方向想。

想法是建立一个2维的boolean数组,booleen[][] check = new boolean[s.length()+1][p.length()+1],注意最好比string的length大一行和一列,来包括第0行和第0列的情况。这样初始化比较方便。check[m][n]表示s的前m个元素是否与p的前n个元素match。最后右下元素check[s.length()][p.length()]即我们所求。

维护量找到了,下一步要做的就是找到转移关系。这里思考的时候可能不能把关系理的很清楚。这里要点如下:
1. 如果s.charAt(m) 或者 p.charAt(n)是‘*’, 那么如果check[m-1][n]或者check[m][n-1]为真,check[m][n]为真

2. 如果check[m-1][n-1]为真,表示s的前m-1个元素与p的前n-1个元素是matched,那么只需要判断s的第m个和p的第n个。match有很多情况,可以是值相等,也可以某一个元素为‘*’或‘?’

时间复杂度是一个两层循环O(M*N), 空间复杂度是一个O(M*N)的矩阵。

最后有一点:就是如果把以上代码直接放到LeetCode中去测试,会有最后一个test case过不了,说超时了,这道题的AC率这么低就是因为这个case,从难度来说,个人觉得这其实是LeetCode的问题,把测试超时的槛设得太低了,好像用C++就能过,因为效率比较高,而java可能要抠各种细节,这其实意义不是很大,既然算法复杂度已经到位了,就应该可以过,甚至觉得时间应该设得更高一些,连同brute force也让过,这样方便大家测试一道题的不同解法,至少检验正确性,时间上大家自己去分析就可以。所以第6行用了那段代码跳过那个case。

 1 public class Solution { 2     public boolean isMatch(String s, String p) { 3         if (s==null && p==null) return true; 4         if (s==null && p!=null) return false; 5         if (s!=null && p==null) return false; 6         if(s.length()>300 && p.charAt(0)==‘*‘ && p.charAt(p.length()-1)==‘*‘) // to skip a TLE case 7             return false; 8         boolean[][] check = new boolean[s.length()+1][p.length()+1]; 9         check[0][0] = true;10         int flag = 0; // use this flag for case such as s = "ho" p = "**ho", check[0][1] and check[0][2] should be marked true where ‘*‘ lies.11         for (int i=1; i<=s.length(); i++) {12             if (s.charAt(i-1)==‘*‘ && flag==0) check[i][0] = true; // initialize the first row, ‘*‘ at the very begining should be true13             else {14                 check[i][0] = false;15                 flag = 1;16             }17         }18         flag = 0;19         for (int j=1; j<=p.length(); j++) { // initialize the first column20             if (p.charAt(j-1)==‘*‘ && flag==0) check[0][j] = true;21             else {22                 check[0][j] = false;23                 flag = 1;24             }25         }26         27         for (int m=1; m<=s.length(); m++) {28             for (int n=1; n<=p.length(); n++) {29                 if ((s.charAt(m-1)==‘*‘ || p.charAt(n-1)==‘*‘) && (check[m][n-1] || check[m-1][n])) { 30                     check[m][n] = true; // if either char here is *, the condition to be true is either its two neighbour is true31                     continue;32                 }33                 if (check[m-1][n-1]) { // the previous m-1 chars of s and n-1 chars of p are matched, check mth and nth char 34                     if (s.charAt(m-1)==p.charAt(n-1) || s.charAt(m-1)==‘?‘ || s.charAt(m-1)==‘*‘ || p.charAt(n-1)==‘?‘ || p.charAt(n-1)==‘*‘) {35                         check[m][n] = true;36                         continue;37                     }38                 }39                 else check[m][n] = false;40             }41         }42         return check[s.length()][p.length()];43     }44 }

Code Ganker用1维DP做了这个问题,尚未深究,但是2维DP想起来容易一些,也更是做这种题的套路

 1 public boolean isMatch(String s, String p) { 2     if(p.length()==0) 3         return s.length()==0; 4     boolean[] res = new boolean[s.length()+1]; 5     res[0] = true; 6     for(int j=0;j<p.length();j++) 7     { 8         if(p.charAt(j)!=‘*‘) 9         {10             for(int i=s.length()-1;i>=0;i--)11             {12                 res[i+1] = res[i]&&(p.charAt(j)==‘?‘||s.charAt(i)==p.charAt(j));13             }14         }15         else16         {17             int i = 0;18             while(i<=s.length() && !res[i])19                 i++;20             for(;i<=s.length();i++)21             {22                 res[i] = true;23             }24         }25         res[0] = res[0]&&p.charAt(j)==‘*‘;26     }27     return res[s.length()];28 }

 

Leetcode: Wildcard Matching