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

[balabla] 算法的时间复杂度是O(m * n), 空间复杂度是O(n), m, n分别为p 和 s 的长度。

一开始使用纯二维数组,提交时会遇到OutOfMemory错误,事实上确实只要两个一维数组就行。

使用二维数组来描述思路:

dp[i][j] 表示 p的前i个字符能否匹配s的前j个字符,递推公式分两大情况:

1)如果p的当前字符非 * 号,dp[i][j] == dp[i-1][j-1] && (charP == charS || charP == '?');

2)如果p的当前字符是 * 号,分3种情况讨论:

a) ' * ' 匹配0次:dp[i][j] = dp[i - 1][j]

b) ' * ' 匹配1次:dp[i][j] = dp[i - 1][j - 1]

c) ' * '匹配次数>1:dp[i][j] = dp[i][j - 1]

dp[i][j]的值是三种情况的并集, dp[i][j] == dp[i - 1][j] || dp[i-1][j-1] || dp[i][j - 1]

可以看到dp[i][j] 至多只需看上一行同列和对角以及本行前一列的元素,

因此只需要两个一维数组保存中间结果就可以。

两个一维数组循环使用需要注意line32 & 33行的赋值不可省,因为数组存储上一次循环的旧值。

同意博客http://blog.csdn.net/linhuanmars/article/details/21198049 说的,这题算法复杂度已经到位,

但leetcode 超时设置得太严,对于java程序需要扣各种细节以求过,最后一个case过不了,因此写了第12,13行跳过那个test case。

方法二是实现博客中只需要一维数组的做法,借鉴其精简空间的思路。

方法三也是参考网上,是贪婪思想,能直接过大数据测试,时间复杂度说O(n)我觉得不准确,但也不知如何分析

public class WildcardMatching {
    
    // Method1: Time: O(m * n), Space: O(n),两个一维数组
    // dp[i][j] : p的前i个字符能否匹配s的前j个字符
    public boolean isMatch1(String s, String p) {
        if (p == null || s == null)
            return false;
        int lengthS = s.length();
        int lengthP = p.length();
        if (lengthS > 300 && p.charAt(0) == '*' && p.charAt(lengthP - 1) == '*')
            return false;
        boolean[][] dp = new boolean[2][lengthS + 1];
        dp[0][0] = true;
        int lastRow = 1;
        int currRow = 0;
        for (int i = 1; i <= lengthP; i++) {
            lastRow = currRow;
            currRow = 1 - lastRow;
            char charP = p.charAt(i - 1);
            dp[currRow][0] = dp[lastRow][0] && charP == '*';
            for (int j = 1; j <= lengthS; j++) {
                char charS = s.charAt(j - 1);
                if (charP == charS || charP == '?') {
                    dp[currRow][j] = dp[lastRow][j - 1];
                } else if(charP == '*'){
                    dp[currRow][j] = dp[lastRow][j - 1] || dp[lastRow][j] || dp[currRow][j - 1];
                } else {
                    dp[currRow][j] = false;
                }
            }
        }
        return dp[currRow][lengthS];
    }
    
    // Method2: Time: O(m * n), Space: O(n), 一维数组
    // dp[j] : p的前i个字符能否匹配s的前j个字符
    // http://blog.csdn.net/linhuanmars/article/details/21198049
    public boolean isMatch2(String s, String p) {
        if (p == null || s == null)
            return false;
        int lengthS = s.length();
        int lengthP = p.length();
        if (lengthS > 300 && p.charAt(0) == '*' && p.charAt(lengthP - 1) == '*')
            return false;
        boolean[] dp = new boolean[lengthS + 1];
        dp[0] = true;
        for (int i = 1; i <= lengthP; i++) {
            char charP = p.charAt(i - 1);
            if (charP != '*') {
                for (int j = lengthS; j >= 1; j--) {
                    dp[j] = dp[j - 1] && (charP == s.charAt(j - 1) || charP == '?');
                }
            } else {
                int j = 0;
                while (j <= lengthS && !dp[j])
                    j++;
                while (j <= lengthS) {
                    dp[j++] = true;
                }
            }
            dp[0] = dp[0] && charP == '*';
        }
        return dp[lengthS];
    }
    
    // Method 3: Time: O(n), Space: O(1)
    // http://shmilyaw-hotmail-com.iteye.com/blog/2154716
    public boolean isMatch3(String str, String pattern) {
        int s = 0, p = 0, match = 0, starIdx = -1;
        int lengthP = pattern.length();
        int lengthS = str.length();
        while (s < lengthS) {
            if (p < lengthP && (pattern.charAt(p) == str.charAt(s) || pattern.charAt(p) == '?')) {
                s++;
                p++;
            } else if (p < lengthP && pattern.charAt(p) == '*') {
                starIdx = p;
                match = s;
                p = starIdx + 1;
            } else if (starIdx != -1) {
                p = starIdx + 1;
                match++;
                s = match;
            } else {
                return false;
            }
        }
        // deal with remaining character in pattern
        while (p < lengthP && pattern.charAt(p) == '*') {
            p++;
        }
        return p == lengthP;
    }
}

猜你喜欢

转载自likesky3.iteye.com/blog/2217581