LeetCode - Wildcard Matching

来源:互联网 发布:java卸载不了怎么办 编辑:程序博客网 时间:2024/05/24 06:03

https://leetcode.com/problems/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
这道题一看就是用动态规划做,我一开始用二维数组做的,结果memory limit exceeded了,而且,中间细节很容易错,一定要考虑好。

如果在位置i 遇到‘*’的话,则,只要i-1有match的,那么,从i一直到结束都可以match了

public class Solution {    public boolean isMatch(String s, String p) {        if(s==null && p==null) return true;        if(s.length()==0 && p.length()==0) return true;         boolean[][] match = new boolean[s.length()+1][p.length()+1];         for(int i=0; i<match.length; i++) Arrays.fill(match[i], false);                  match[0][0] = true;                  for(int i=1; i<=s.length(); i++){             for(int j=1; j<=p.length(); j++){                 if(match[i][j]) continue;                 if(s.charAt(i-1) == '*'){                     int k = j;                     while(k>=0 && !match[i-1][k]) k--;                     if(k>=0){                        for(; k<=p.length(); k++) match[i][k] = true;                     }                     else match[i][j] = false;                 }                 if(p.charAt(j-1) == '*'){                     int k = i;                     while(k>=0 && !match[k][j-1]) k--;                     if(k>=0){                         for(; k<=s.length(); k++) match[k][j] = true;                     }                 }                 if(!match[i][j]){                     if(s.charAt(i-1)=='?' || p.charAt(j-1) == '?' || s.charAt(i-1)==p.charAt(j-1)) match[i][j] = match[i-1][j-1];                     else match[i][j] = false;                 }                              }         }         return match[s.length()][p.length()];    }}

发现大神们居然都是用一维数组做的,真的跪了。。。。。

注意:

match[0] = match[0]&&p.charAt(i-1)=='*';
这里是循环里每次都需要更新match[0]的值,只有p在当前位置之前全是 * 才能匹配空字符串,所以,这里只看当前位置的值和之前的match[0]。

并且,由于循环里更新数组是从后往前更新,所以match[0]的值是最后更新的。

    public boolean isMatch(String s, String p) {        if(s==null && p==null) return true;        if(s.length()==0 && p.length()==0) return true;        if(s.length()>300 && p.charAt(0)=='*' && p.charAt(p.length()-1)=='*')  return false;          boolean[] match = new boolean[s.length()+1];        match[0] = true;                  for(int i=1; i<=p.length(); i++){             if(p.charAt(i-1)=='*'){                 int k=0;                 while(k<=s.length() && !match[k]) k++;                 while(k<=s.length()){                     match[k] = true;                     k++;                 }             }             else{                for(int j=s.length(); j>0; j--){                    if(s.charAt(j-1)=='?' || p.charAt(i-1)=='?' || p.charAt(i-1)==s.charAt(j-1)) match[j] = match[j-1];                    else match[j] = false;                }             }             match[0] = match[0]&&p.charAt(i-1)=='*';                      }                  return match[s.length()];    }


不过第二个一维数组的解有个问题,就是被匹配的string s里面不能有‘*’ 或者 '?' ,但是leetcode 也能过,可能这题目的意思就是s里面不能有这些匹配符,只是没有说清楚吧。

二维数组的解法就是s里面有‘*’ 或者 ‘?’ 也是可以匹配的。所以,如果两个string都有匹配符的话,还是应该用二维数组的哈。

另外,DP做的话,时间复杂度是 O(m*n)最后两个大case的时间复杂度是过不了的,所以在代码最开始加了一行跳过了这两个大case。

这道题还有不用DP,但是时间复杂度更低的解法:

http://fisherlei.blogspot.com/2013/01/leetcode-wildcard-matching.html


我把这个解法用JAVA写了一遍,就是记录上一个star出现的位置,然后用p后面非star的字母跟s后面的字母匹配,凡是匹配不上的全部看作和star匹配了。

这种解法是在发现不匹配时回到星号的位置重新匹配,不匹配有两种情况,一是当前的两个字母不相等,一是p已经结束了,s还没有结束。

我上面贴的网址里的解法是C++的,很奇怪的是他没有处理p已经结束的情况。。。。后来发现原来C++里面有一个字符串结束符,*ptr为'\0'表示结束,这时候不会溢出,但这时候就会进入default里面,即两个字母不相同的情况,但JAVA里面是取的p.charAt(j),到最后一个j=p.length()的时候,这个函数就溢出了。所以JAVA里面必须把这种情况单独拿出来。这种解法有时候是O(n),有时候是O(n^2),看字符串匹配情况。。。不过这个解法倒是能过leetcode的最后的大数据。

public class Solution {    public boolean isMatch(String s, String p) {        if(s==null && p==null) return true;        if(p.length()==0) return s.length()==0;  //如果p为空,只有s为空的时候才能匹配                int ts = 0; int tp = 0;        boolean star = false;        int i, j;        for(i=0, j=0; i<s.length(); i++, j++){            switch(p.charAt(j)){                case '?': break;  //问号不管s当前是什么都能匹配,所以跳过                case '*':                    star = true;                    while(j<p.length() && p.charAt(j) == '*') j++;  //如果p的星号后面没有字母了,那么匹配结束了                    if(j==p.length()) return true;                    ts = i;                    tp = j;                    i = ts -1;                    j = tp -1;                    break;                default:                    if(s.charAt(i) == p.charAt(j)) break;                    else{  //如果当前s的字母和p的字母匹配不上,那么回到星号后面的地方,重新开始                        if(!star) return false;                        ts++;                        i = ts - 1;                        j = tp - 1;                    }            }            if((j+1)==p.length()){  //当p已经用完了,s如果也完了,那么匹配上了            if((i+1)==s.length()) return true;            else{                if(star){   //当p已经结束,s没有结束时,看是否有星号,如果有星号,则回到星号后重新匹配,没有星号就说明没有匹配上                    ts++;                i = ts -1;                j = tp -1;                }                else return false;            }            }        }        while(j<p.length() && p.charAt(j) == '*') j++;        return j==p.length();    }}




0 0
原创粉丝点击