​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表格

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

第一次做; 暴力递归改动态规划; 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;
}
}