LeetCode Top Interview Questions 44. Wildcard Matching (Java版; Hard)

welcome to my blog

LeetCode Top Interview Questions 44. Wildcard Matching (Java版; Hard)

题目描述
Given an input string (s) and a pattern (p), 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).

Note:

s could be empty and contains only lowercase letters a-z.
p could be empty and contains only lowercase letters a-z, and characters like ? or *.
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'.
Example 4:

Input:
s = "adceb"
p = "*a*b"
Output: true
Explanation: The first '*' matches the empty sequence, while the second '*' matches the substring "dce".
Example 5:

Input:
s = "acdcb"
p = "a*c?b"
Output: false
//递归版超时后改成了dp版
class Solution {
    public boolean isMatch(String s, String p) {
        int n = s.length(), m = p.length();
        //dp[i][j]表示s的前i个字符是否和p的前j个字符匹配
        //dp[i][j] = p[j-1]=='*'
        boolean[][] dp = new boolean[n+1][m+1];
        dp[0][0] = true;
        for(int j=1; j<=m; j++){
            dp[0][j] = dp[0][j-1] && (p.charAt(j-1)=='*');
        }
        for(int i=1; i<=n; i++){
            for(int j=1; j<=m; j++){
                char ch = p.charAt(j-1);
                if(ch=='*'){
                    dp[i][j] = dp[i][j-1] || dp[i-1][j-1] || dp[i-1][j];
                }else if(ch=='?' || ch==s.charAt(i-1)){
                    dp[i][j] = dp[i-1][j-1];
                }
            }
        }
        return dp[n][m];
    }
}
dp表格

第一次做; 暴力递归改动态规划; dp[i][j]表示s的前i个字符是否和p的前j个字符匹配; 我的做法:根据递归函数可知是两个可变参数, 所以是个二维dp; 画一个二维表格, 看暴力递归函数处理逻辑联想dp的递推公式, 然后填好二维表格的第一行和第一列, 最后根据递推公式完成递归主体
/*
暴力递归改动态规划
*/
class Solution {
    public boolean isMatch(String s, String p) {
        int n = s.length();
        int m = p.length();
        boolean[][] dp = new boolean[n+1][m+1];
        //initialize
        dp[0][0]=true;
        for(int j=0; j<m; j++){
            if(p.charAt(j)=='*')
                dp[0][j+1]=true;
            else
                break;
        }
        //dp主体
        char ch1, ch2;
        for(int i=1; i<=n; i++){
            ch1 = s.charAt(i-1);
            for(int j=1; j<=m; j++){
                ch2 = p.charAt(j-1);
                if(ch1==ch2)
                    dp[i][j] = dp[i-1][j-1];
                else if(ch2=='?')
                    dp[i][j] = dp[i-1][j-1];
                else if(ch2=='*')
                    //不匹配; 匹配一次; 匹配多次
                    dp[i][j] = dp[i][j-1] || dp[i-1][j-1] || dp[i-1][j];
            }
        }
        return dp[n][m];
    }
}
第一次做; 使用memo数组优化暴力递归; 核心: 什么情况下能使用memo数组优化暴力递归? [i,end]的状态和[0,i-1]无关时可以, 本题就是这样, 如果索引来到i, 就不用考虑[0,i-1]的情况了; 之前的背包问题就不能用memo数组, 因为即使索引来到i,最终的结果仍然和[0,i-1]有关
/*
使用memo数组优化暴力递归
*/
import java.util.Arrays;


class Solution {
    public boolean isMatch(String s, String p) {
        int[][] memo = new int[s.length()][p.length()];
        for(int[] m : memo){
            Arrays.fill(m, -1);
        }
        return core(memo, s, p, 0, 0);
    }
    //递归函数逻辑s的[i,s.length()-1]部分和p的[j,p.length()-1]部分是否匹配
    public boolean core(int[][] memo, String s, String p, int i, int j){
        //base case
        if(j==p.length() && i==s.length())
            return true;
        if(j==p.length() && i!=s.length())
            return false;
        if(j!=p.length() && i==s.length()){
            for(int t=j; t<p.length(); t++){
                if(p.charAt(t)!='*')
                    return false;
            }
            return true;
        }
        if(memo[i][j]!=-1)
            return memo[i][j]==1?true:false;
        //
        boolean flag=false;
        char ch1 = s.charAt(i);
        char ch2 = p.charAt(j);
        if(ch1==ch2){
            flag = core(memo, s, p, i+1, j+1);
        }
        else if(ch2=='?'){
            flag = core(memo, s, p, i+1, j+1);
        }
        else if(ch2=='*'){
            //不匹配; 匹配一次; 匹配多次
            flag = core(memo, s, p, i, j+1) || core(memo, s, p, i+1, j+1) || core(memo, s, p, i+1, j);
        }
        else{
            flag = false;
        }
        //update memo
        memo[i][j] = flag==true?1:0;
        return flag;
    }
}
第一次做; 暴力递归; 超时1614 / 1809
/*
通配符匹配, 和正则表达式匹配不同!
先试试暴力递归
*/
class Solution {
    public boolean isMatch(String s, String p) {
        return core(s, p, 0, 0);
    }
    public boolean core(String s, String p, int i, int j){
        //base case
        if(i==s.length() && j==p.length())
            return true;
        if(i!=s.length() && j==p.length())
            return false;
        if(i==s.length() && j!=p.length()){
            for(int t=j; t<p.length(); t++){
                if(p.charAt(t)!='*')
                    return false;
            }
            return true;
        }
        //here, i!=s.length() && j!=p.length()
        boolean flag = false;
        char ch = p.charAt(j);
        if(ch==s.charAt(i))
            flag = core(s, p, i+1, j+1);
        else if(ch=='?')
            flag = core(s, p, i+1, j+1);
        else if(ch=='*')
            //不匹配, 匹配一次, 匹配多次
            flag = core(s, p, i, j+1) ||core(s, p, i+1, j+1) || core(s, p, i+1, j);
        else
            flag = false;
        return flag;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值