Wildcard Matching
LeetCode #44
Description:
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).
The function prototype should be: bool isMatch(const char s, const char p)
Example:
Some examples:
isMatch("aa","a") → false
isMatch("aa","aa") → true
isMatch("aaa","aa") → false
isMatch("aa", "*") → true
isMatch("aa", "a*") → true
isMatch("ab", "?*") → true
isMatch("aab", "c*a*b") → false
Idea:
方法一: time O(n2) / dp[i+1][j+1]: p[0-i] match s[0-j] or not? p[j-1] == s[i-1] || p[j-1] == '?':dp[i][j] = dp[i-1][j-1] p[j-1] == '':
- 匹配0个字符:dp[i][j] = dp[i][j-1]
- 匹配1个字符:dp[i][j] = dp[i-1][j-1]
- 匹配多个字符:dp[i][j] = dp[i-1][j] */
方法二:time: O(n) /* 假设我们用两个指针分别指向s和p字符串中要匹配的位置,首先分析下通配符匹配过程中会有哪些情况是成功:
- s的字符和p的字符相等
- p中的字符是?,这时无论s的字符是什么都可以匹配一个
- p中遇到了一个*,这时无论s的字符是什么都没关系
- 之前的都不符合,但是p在之前的位置有一个,我们可以从上一个后面开始匹配
- s已经匹配完,但是p后面还有很多连续的` 这里1和2的情况比较好处理,关键在于如何处理3和4的情况。当我们遇到一个时,因为之后可能要退回至该位置重新匹配,我们要将它的下标记录下来,比如idxstar。 但是,当我们连续遇到两次4的情况,如何保证我还是能继续匹配s,而不是每次都退回idxstar+1导致循环呢?所以我们还要记录一个idxmatch,用来记录用上一个连续匹配到的s中的下标。 最后,对于情况5,我们用一个循环跳过末尾的跳过就行了。 */
Code:
Method 1 Time: O(n)
class Solution {
public:
bool isMatch(string s, string p){
int inds=0, indp=0, indpstar=-1, indsmatch=0;
int M=s.size();
int N=p.size();
while(inds<M){
if(indp<N && (s[inds]==p[indp] || p[indp]=='?')){
indp++;
inds++;
}
else if(indp<N && p[indp]=='*'){
indpstar=indp;
indp++;
indsmatch=inds;
}
else if(indpstar!=-1){
inds=indsmatch;
indsmatch++;
indp=indpstar+1;
}
else{
return false;
}
}
// 因为1个*能匹配无限序列,如果p末尾有多个*,我们都要跳过
while(indp<N && p[indp]=='*'){
indp++;
}
// 如果p匹配完了,说明匹配成功
return indp==p.size();
}
};
Method 2
#include <iostream>
#include <vector>
#include <climits>
#include <cassert>
using namespace std;
/*
dp[i+1][j+1]: p[0-i] match s[0-j] or not?
p[j-1] == s[i-1] || p[j-1] == '?':dp[i][j] = dp[i-1][j-1]
p[j-1] == '*':
1. 匹配0个字符:dp[i][j] = dp[i][j-1]
2. 匹配1个字符:dp[i][j] = dp[i-1][j-1]
3. 匹配多个字符:dp[i][j] = dp[i-1][j]
*/
bool isMatch(string s, string p) {
int M=s.size();
int N=p.size();
vector<vector<bool>> dp(M+1, vector<bool>(N+1, false));
dp[0][0]=true;
for(int i=0; i<=M; ++i){ // i must start from 0, because even if s is empty, p can still match it. But if p is empty, s can only be empty
for(int j=1; j<=N; ++j){
if(i>0 && (s[i-1]==p[j-1] || p[j-1]=='?')){
dp[i][j]=dp[i-1][j-1];
}
else if(p[j-1]=='*'){
if(i==0)
dp[i][j]=dp[i][j-1];
else
dp[i][j]=dp[i][j-1]||dp[i-1][j-1]||dp[i-1][j];
}
}
}
return dp[M][N];
}
int main(){
assert(isMatch("aaaaaaaa", "c")==false);
assert(isMatch("aa", "a?")==true);
assert(isMatch("aaa", "aa")==false);
assert(isMatch("aa", "*")==true);
assert(isMatch("aa", "a*")==true);
assert(isMatch("aa", "?*")==true);
assert(isMatch("aa", "c*a*b")==false);
assert(isMatch("abc", "**d")==false);
}