算法学习之动态规划(leetcode 44 Wildcard Matching)

leetcode 44. 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

解题思路,首先先弄明白?和*在其中的含义,

     - ?代表一个的意思
     - *代表0个或者多个的意思

然后自己考虑的时候,需要使用到动态规划的想法,就是构建一个2D表格,进行一个递推过程。首先,明确定义,定义二维布尔矩阵dp[m][n],第一个坐标为待匹配的字符串,第二个坐标为模式串,dp[x][y]的含义是字符串前x个字符与模式串前y个字符是否匹配,若匹配则为true,否则为false.

递推核心过程如下,
如果当前需要判断dp[i+1][j+1],即字符串的下标到达i,模式串的下标到达j。此时,分为两种情况

 1. p.charAt(j) == '?' || s.charAt(i) == p.charAt(j)。
    含义是如果p为此处字符为?或者p此处的字符与s此处的字符相同,
    则显然dp[i+1][j+1] = dp[i][j]
 2. p.charAt(j) == '*'。这种情况较为复杂。分情况讨论。
     A. *代表0个字符,则此时dp[i+1][j+1]=dp[i+1][j]
     B. *代表1个字符,则此时dp[i+1][j+1]=dp[i][j]
     C. *代表2个字符,则此时dp[i+1][j+1]=dp[i-1][j]
     D. *代表3个字符,则此时dp[i+1][j+1]=dp[i-2][j]
     ...
     因此,最后的统一结果为
     dp[i+1][j+1]=dp[i+1][j] || dp[i][j] || dp[i-1][j] || 
                  dp[i-2][j] || ... || dp[0][j]
     需要注意的是按照上述公式,可以得到
     dp[i][j+1] = dp[i][j] || dp[i-1][j] || dp[i-2][j] ||  
                  dp[i-3][j] || ... || dp[0][j]
     因此dp[i+1][j+1] = dp[i+1][j] || dp[i][j+1]   
 3. s.charAt(i) != p.charAt(j) 不匹配
     dp[i+1][j+1] = false;

需要注意的细节为
1 需要二维布尔矩阵开始全部初始化为false,然后将dp[0][0]=true,将第0行进行初始化,dp[0][j+1] = dp[0][j] && (p.charAt(j) == ‘*’),此句话的意思是如果前面匹配,当前为 *,则肯定匹配。
2 先统计下p中非*的有多少,如果比s的总字符长度还大,说明没有必要继续做下去了(不可能匹配成功)。
具体的代码实现

public class Solution {
    public boolean isMatch(String s, String p) {
        if(s == null || p == null) return true;

        int sLen = s.length();
        int pLen = p.length();

        //非star数目统计
        int countNotStar = 0;
        for(int i = 0; i < pLen; i++){
            if(p.charAt(i) != '*'){
                countNotStar += 1;
            }
        }
        //如果非star数目比s长度还大,不可能匹配
        if(countNotStar > sLen) return false;

        //初始化二维矩阵,全为false
        boolean[][] dp = new boolean[sLen+1][pLen+1];
        dp[0][0] = true;

        for(int j = 0; j < pLen; j++){
            //初始化第一行数据
            dp[0][j+1] = dp[0][j] && (p.charAt(j) == '*');

            for(int i = 0; i < sLen; i++){
                //情况1
                if(p.charAt(j) == '?' || p.charAt(j) == s.charAt(i)){
                    dp[i+1][j+1] = dp[i][j];
                }
                //情况2
                else if(p.charAt(j) == '*'){
                    dp[i+1][j+1] = (dp[i][j+1] || dp[i+1][j]);
                }
                //not match
                else{
                    dp[i+1][j+1] = false;
                }
            }
        }

        return dp[sLen][pLen];
    }
}

你可能感兴趣的:(leetcode算法学习)