【LeetCode】No.44. Wildcard Matching -- Java Version

266 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第22天。

题目链接: leetcode.com/problems/wi…

1. 题目介绍(Wildcard Matching)

Given an input string (s) and a pattern (p), implement wildcard pattern matching with support for '?' and '*' where:

【Translate】: 给定输入字符串(s)和模式( p ),实现通配符模式匹配,并要求支持'?'和'*'

  • '?' Matches any single character.
  • '*' Matches any sequence of characters (including the empty sequence).

【Translate】: “?”匹配任何单个字符; '*'匹配任何字符序列(包括空序列)。

The matching should cover the entire input string (not partial).

【Translate】: 匹配应该覆盖整个输入字符串(而不是部分)。

【测试用例】: testcase

【约束】: constrains

2. 题解

2.1 动态规划

  以s="bbaa", p="*a*a"为例,使用动态规划将通配符匹配的问题划分成一个个小的彼此联系的子问题。我后一个的结果和我前一个的结果或者其它结果之间存在联系。如果我从前面就是错的,那么我就一路错到底。   该题解来自于DyXrLxSTAOadoD在leetcode_deleted_user的题解 My java DP solution using 2D table中的评论。这种做法为了可读性浪费了很多额外空间。[0][0]那一层其实不是很需要。

我们可以把通配符匹配问题分为以下三种情况:

  1. 当前的p和s字符相同,或者当前p字符为'?'
  2. 当前p字符为'*'
  3. 不符合上述两种条件的其它情况

  第一种情况,如果符合,那么就说明当前通配符匹配的是正确的,那么我当前的结果就可以根据我上一层的结果来看,如果上一层就FALSE了,那么我这一层再对,也没什么用,因为从一开始就是错的;

  第二种情况,如果符合,那么我当前的结果就要看我上一层的结果和我前一个的结果,因为'*'可以匹配所有的串,所以说只要前面不出错,后面我肯定对;

  第三种情况,属于啥都不是,直接FALSE。

demo1

    public boolean isMatch(String s, String p) {
      int m = s.length(), n = p.length();
      char[] sc = s.toCharArray();
      char[] pc = p.toCharArray();
      boolean[][] dp = new boolean[m + 1][n + 1];
      dp[0][0] = true;
      for(int j = 1; j < n + 1; j++){
        if(pc[j - 1] == '*') dp[0][j] = dp[0][j - 1]; 
      }   
      
      for(int i = 1; i < m + 1; i++){
        for(int j = 1; j < n + 1; j++){
          if(pc[j - 1] == sc[i - 1] || pc[j - 1] == '?'){
            dp[i][j] = dp[i - 1][j - 1];
          } else if(pc[j - 1] == '*'){
            dp[i][j] = dp[i - 1][j] || dp[i][j - 1];
          } else {
            dp[i][j] = false;
          }
        }
      }
      return dp[m][n];
    }

case1

2.2 双指针

  该题解来自于pandora111的 Linear runtime and constant space solution,其基本思想是用一个指针指向str,一个指针指向pattern。这个算法最多迭代length(str)+length(pattern)次,对于每次迭代,至少有一个指针向前推进一步。

class Solution {
    public boolean isMatch(String str, String pattern) {
        int s = 0, p = 0, match = 0, starIdx = -1;            
        while (s < str.length()){
            // advancing both pointers
            if (p < pattern.length()  && (pattern.charAt(p) == '?' || str.charAt(s) == pattern.charAt(p))){
                s++;
                p++;
            }
            // * found, only advancing pattern pointer
            else if (p < pattern.length() && pattern.charAt(p) == '*'){
                starIdx = p;
                match = s;
                p++;
            }
           // last pattern pointer was *, advancing string pointer
            else if (starIdx != -1){
                p = starIdx + 1;
                match++;
                s = match;
            }
           //current pattern pointer is not star, last patter pointer was not *
          //characters do not match
            else return false;
        }
        
        //check for remaining characters in pattern
        while (p < pattern.length() && pattern.charAt(p) == '*')
            p++;
        
        return p == pattern.length();
    }
}

case2