Problem Statement:

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

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

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

Example 1: Input: s = “aa”, p = “a” Output: false Explanation: “a” does not match the entire string “aa”.

Example 2: Input: s = “aa”, p = "" Output: true Explanation: '' matches any sequence.

Example 3: Input: s = “cb”, p = “?a” Output: false Explanation: ’?’ matches ‘c’, but the second letter is ‘a’, which does not match ‘b’.

Solution:

1. Recursive and memoization:
class Solution {
    public boolean isMatch(String s, String p) {
        Boolean[][] memo = new Boolean[s.length() + 1][p.length() + 1];
 
        return isMatchUtil(s, p, 0, 0, memo);
    }
 
    public boolean isMatchUtil(String s, String p, int i, int j, Boolean[][] dp){
        if(i == s.length() && j == p.length()){
            return true;
        }
 
        if(j == p.length()){
            return false;
        }
 
        if(i == s.length()){
            for(int k = j; k < p.length(); k++){
                if(p.charAt(k) != '*'){
                    return false;
                }
            }
            return true;
        }
	    
	    if(dp[i][j] != null){
            return dp[i][j];
        }
 
 
        if(s.charAt(i) == p.charAt(j) || p.charAt(j) == '?'){
            return dp[i][j] = isMatchUtil(s, p, i + 1, j + 1, dp);
        } else if(p.charAt(j) == '*'){
            return dp[i][j]  = isMatchUtil(s, p, i, j + 1, dp) || isMatchUtil(s, p, i + 1, j, dp);
        } else{
            return dp[i][j] = false;
        }
    }
}
2. Tabulation:
class Solution {
    public boolean isMatch(String s, String p) {
        int m = s.length();
        int n = p.length();
        boolean[][] dp = new boolean[m + 1][n + 1];
 
        //Base case: both strings are empty
        dp[0][0] = true;
 
        // Base case: Pattern p contains only '*' at the beginning
        for(int j = 1; j <= n; j++){
            if(p.charAt(j - 1) == '*'){
                dp[0][j] = dp[0][j - 1];
            }
        }
 
        for(int i = 1; i <= m; i++){
            for(int j = 1; j <= n; j++){
                if(s.charAt(i - 1) == p.charAt(j - 1) || p.charAt(j - 1) == '?'){
                    dp[i][j] = dp[i - 1][j - 1];
                } else if(p.charAt(j - 1) == '*'){
                    dp[i][j]  = dp[i][j - 1] || dp[i - 1][j];
                } else{
                    dp[i][j] = false;
                }
            }
        }
        
        return dp[m][n];
    }
}
3. Tabulation and Space optimized:
class Solution {
    public boolean isMatch(String s, String p) {
        int m = s.length();
        int n = p.length();
        boolean[] prev = new boolean[n + 1];
        boolean[] curr = new boolean[n + 1];
 
        //Base case: both strings are empty
        prev[0] = true;
 
        // Base case: Pattern p contains only '*' at the beginning
        for(int j = 1; j <= n; j++){
            if(p.charAt(j - 1) == '*'){
                prev[j] = prev[j - 1];
            }
        }
 
        for(int i = 1; i <= m; i++){
            for(int j = 1; j <= n; j++){
                if(s.charAt(i - 1) == p.charAt(j - 1) || p.charAt(j - 1) == '?'){
                    curr[j] = prev[j - 1];
                } else if(p.charAt(j - 1) == '*'){
                    curr[j]  = curr[j - 1] || prev[j];
                } else{
                    curr[j] = false;
                }
            }
            prev = curr.clone();
        }
        
        return prev[n];
    }
}