44. Wildcard Matching

给定一个字符串 (s) 和一个字符模式 (p) ,实现一个支持 '?' 和 '*' 的通配符匹配。

'?' 可以匹配任何单个字符。
'*' 可以匹配任意字符串(包括空字符串)。

两个字符串完全匹配才算匹配成功。

说明:

s 可能为空,且只包含从 a-z 的小写字母。
p 可能为空,且只包含从 a-z 的小写字母,以及字符 ? 和 *。

刚开始想到的一个方法就是做递归,情况可以分为如下几种

  • s空串且p空串,返回true
  • s不为空但p为空,返回false
  • s为空但p不为空,根据p做判断,如果p的第一个字符是'*',可以继续递归下去,否则返回false
  • s不为空且p不为空,这个时候就要考虑多种情况了。

代码如下:

    public boolean isMatch(String s, String p) {
        if (s == null || p == null) {
            return false;
        }

        if (p.equals("")) {
            return s.equals("");
        } else {
            if (s.equals("")) {
                return p.charAt(0) == '*' && isMatch(s, p.substring(1));
            } else {
                if (p.charAt(0) == '?') {
                    return isMatch(s.substring(1), p.substring(1));
                } else if (p.charAt(0) == '*') {
                    // 空、一次或者多次
                    return isMatch(s, p.substring(1)) || isMatch(s.substring(1), p) || isMatch(s.substring(1), p.substring(1));
                } else {
                    return s.charAt(0) == p.charAt(0) && isMatch(s.substring(1), p.substring(1));
                }
            }
        }
    }

最重要的是理解,当p的第一个字符是'*'的情况,可以匹配零次、一次或者多次。但是很不幸的是,上面的方法超时了,确实,本来这样递归就是很耗时间,因为很多重复的计算。

后来看了一下别人的一个动态规划方法,也跟着写了一下,代码如下:

    public boolean isMatch(String s, String p) {
        if (s == null || p == null) {
            return false;
        }

        int lenS = s.length();
        int lenP = p.length();
        boolean[][] dp = new boolean[lenP+1][lenS+1];
        dp[0][0] = true;

        for (int i = 1;i <= lenP;++i) {
            dp[i][0] = p.charAt(i-1) == '*' && dp[i-1][0];
        }

        for (int i = 1;i <= lenP;++i) {
            for (int j = 1;j <= lenS;++j) {
                if (p.charAt(i-1) == '?') {
                    dp[i][j] = dp[i-1][j-1];
                } else if (p.charAt(i-1) == '*') {
                    dp[i][j] = dp[i-1][j] || dp[i-1][j-1] || dp[i][j-1]; // 零次、一次或多次
                } else {
                    dp[i][j] = (s.charAt(j-1) == p.charAt(i-1)) && dp[i-1][j-1];
                }
            }
        }

        return dp[lenP][lenS];
    }

重要的还是需要理解是如何匹配零次、一次或者多次。

你可能感兴趣的:(44. Wildcard Matching)