Comment on page

44.Wildcard-Matching

44. Wildcard Matching

题目地址

题目描述

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

代码

Approach 1: DFS

class Solution {
public boolean isMatch(String s, String p) {
if (s == null || p == null) return false;
if (s.length() == 0 || p.length() == 0) return false;
​
return dfs(s, 0, p, 0);
}
​
private boolean dfs(String s, int sIdx, String p, int pIdx) {
if (sIdx == s.length() || pIdx == p.length()) {
if (sIdx == s.length() && pIdx == p.length()) {
return true;
} else {
return false;
}
}
​
if (p.charAt(pIdx) == '*') {
// remove continuous *
while (p.charAt(pIdx) == '*')
pIdx++;
if (pIdx == p.length()) return true;
}
​
// compare remaining part of p after * with s
while (sIdx < s.length() && !dfs(s, sIdx, p, pIdx)) {
sIdx++;
}
​
// sIdx 不能为空
return sIdx != s.length();
} else if (s.charAt(sIdx) == p.chaAt(pIdx) || p.charAt(pIdx) == '?') {
return dfs(s, sIdx + 1, p, pIdx + 1);
} else {
return false;
}
}
}

Approach #2 Dynamic Programming

Time complexity : O(SP) && Space complexity : O(SP) to keep the matrix.
class Solution {
public boolean isMatch(String s, String p) {
int sLen = s.length(), pLen = p.length();
​
// base cases
if (p.equals(s) || p.equals("*")) return true;
if (p.isEmpty() || s.isEmpty()) return false;
​
// init all matrix except [0][0] element as False
boolean[][] d = new boolean[pLen + 1][sLen + 1];
d[0][0] = true;
​
// DP compute
for (int pIdx = 1; pIdx < pLen + 1; pIdx++) {
// the current character in the pattern is '*'
if (p.charAt(pIdx - 1) == '*') {
int sIdx = 1;
// d[p_idx - 1][s_idx - 1] is a string-pattern match
// on the previous step, i.e. one character before.
// Find the first idx in string with the previous math.
while ((!d[pIdx - 1][sIdx - 1]) && (sIdx < sLen + 1)) sIdx++;
// If (string) matches (pattern),
// when (string) matches (pattern)* as well
d[pIdx][sIdx - 1] = d[pIdx - 1][sIdx - 1];
// If (string) matches (pattern),
// when (string)(whatever_characters) matches (pattern)* as well
while (sIdx < sLen + 1) d[pIdx][sIdx++] = true;
}
// the current character in the pattern is '?'
else if (p.charAt(pIdx - 1) == '?') {
for (int sIdx = 1; sIdx < sLen + 1; sIdx++)
d[pIdx][sIdx] = d[pIdx - 1][sIdx - 1];
}
// the current character in the pattern is not '*' or '?'
else {
for (int sIdx = 1; sIdx < sLen + 1; sIdx++) {
// Match is possible if there is a previous match
// and current characters are the same
d[pIdx][sIdx] = d[pIdx - 1][sIdx - 1] &&
(p.charAt(pIdx - 1) == s.charAt(sIdx - 1));
}
}
}
return d[pLen][sLen];
}
}

Approach #3 Dynamic Programming - 2

boolean strmatch(String str, String pattern, int n, int m) {
// empty pattern can only match with
// empty string
if (m == 0)
return (n == 0);
​
// lookup table for storing results of
// subproblems
boolean[][] lookup = new boolean[n + 1][m + 1];
​
// initailze lookup table to false
for(int i = 0; i < n + 1; i++)
Arrays.fill(lookup[i], false);
​
​
// empty pattern can match with empty string
lookup[0][0] = true;
​
// Only '*' can match with empty string
for (int j = 1; j <= m; j++)
if (pattern.charAt(j - 1) == '*')
lookup[0][j] = lookup[0][j - 1];
​
// fill the table in bottom-up fashion
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
// Two cases if we see a '*'
// a) We ignore '*'' character and move
// to next character in the pattern,
// i.e., '*' indicates an empty sequence.
// b) '*' character matches with ith
// character in input
if (pattern.charAt(j - 1) == '*')
lookup[i][j] = lookup[i][j - 1] ||
lookup[i - 1][j];
​
// Current characters are considered as
// matching in two cases
// (a) current character of pattern is '?'
// (b) characters actually match
else if (pattern.charAt(j - 1) == '?' ||
str.charAt(i - 1) == pattern.charAt(j - 1))
lookup[i][j] = lookup[i - 1][j - 1];
​
// If characters don't match
else lookup[i][j] = false;
}
}
​
return lookup[n][m];
}

Approach #3 Backtracking

Time complexity : O(min(S,P)) && Space complexity : O(1)
class Solution {
public boolean isMatch(String s, String p) {
int sLen = s.length(), pLen = p.length();
​
int sIdx = 0, pIdx = 0;
int starIdx = -1, sTmpIdx = -1;
while (sIdx < sLen) {
// If the pattern caracter = string character
// or pattern character = '?'
if (pIdx < pLen && (p.charAt(pIdx) == '?' || p.charAt(pIdx) == s.charAt(sIdx))){
++sIdx;
++pIdx;
}
// If pattern character = '*'
else if (pIdx < pLen && p.charAt(pIdx) == '*') {
// Check the situation
// when '*' matches no characters
starIdx = pIdx;
sTmpIdx = sIdx;
++pIdx;
}
// If pattern character != string character
// or pattern is used up
// and there was no '*' character in pattern
else if (starIdx == -1) {
return false;
}
// If pattern character != string character
// or pattern is used up
// and there was '*' character in pattern before
else {
// Backtrack: check the situation
// when '*' matches one more character
pIdx = starIdx + 1;
sIdx = sTmpIdx + 1;
sTmpIdx = sIdx;
}
}
​
// The remaining characters in the pattern should all be '*' characters
for (int i = pIdx; i < pLen; i++)
if (p.charAt(i) != '*') return false;
return true;
}
}