-
Notifications
You must be signed in to change notification settings - Fork 257
/
wildcard-matching.cpp
165 lines (150 loc) · 4.58 KB
/
wildcard-matching.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
// Time: O(m + n), m is length of pattern, n is length of string
// Space: O(1)
// Iteration with greedy
class Solution {
public:
/**
* @param s: A string
* @param p: A string includes "?" and "*"
* @return: A boolean
*/
bool isMatch(const char *s, const char *p) {
int p_pos = 0, s_pos = 0;
int last_s_pos = -1, last_p_pos = -1;
const int s_len = strlen(s), p_len = strlen(p);
while (s_pos < s_len) {
if (p_pos < p_len && (p[p_pos] == s[s_pos] || p[p_pos] == '?')) {
// Matched a char.
++s_pos;
++p_pos;
} else if (p_pos < p_len && p[p_pos] == '*') {
// Matched '*'.
++p_pos;
last_s_pos = s_pos;
last_p_pos = p_pos;
} else if (last_p_pos != -1) {
// Rollback to the last position of '*' plus 1.
// And try next position of last matched one.
++last_s_pos;
s_pos = last_s_pos;
p_pos = last_p_pos;
} else {
// s_pos < s_len && no matched p, no position to retry.
return false;
}
}
// Skip '*' in p.
while (p_pos < p_len && p[p_pos] == '*') {
++p_pos;
}
// Check if pattern is all matched.
return p_pos == p_len;
}
};
// Time: O(m * n), m is length of pattern, n is length of string
// Space: O(m)
// DP solution with rolling window
class Solution2 {
public:
/**
* @param s: A string
* @param p: A string includes "?" and "*"
* @return: A boolean
*/
bool isMatch(const char *s, const char *p) {
const size_t s_len = strlen(s);
const size_t p_len = strlen(p);
// match[i][j] denotes as:
// s[0, i - 1] matches p[0, j - 1] or not.
vector<vector<bool>> match(2, vector<bool>(p_len + 1));
match[0][0] = true;
for (int i = 1; i <= p_len; ++i) {
if (p[i - 1] == '*') {
match[0 % 2][i] = match[0 % 2][i - 1];
}
}
for (int i = 1; i <= s_len; ++i) {
match[i % 2][0] = false;
for (int j = 1; j <= p_len; ++j) {
if (p[j - 1] != '*') {
match[i % 2][j] = match[(i - 1) % 2][j - 1]
&& (s[i - 1] == p[j - 1] || p[j - 1] == '?');
}
else {
match[i % 2][j] = match[i % 2][j - 1] || match[(i - 1) % 2][j];
}
}
}
return match[s_len % 2][p_len];
}
};
// Time: O(m * n), m is length of pattern, n is length of string
// Space: O(m * n)
// DP solution
class Solution3 {
public:
/**
* @param s: A string
* @param p: A string includes "?" and "*"
* @return: A boolean
*/
bool isMatch(const char *s, const char *p) {
const size_t s_len = strlen(s);
const size_t p_len = strlen(p);
// match[i][j] denotes as:
// s[0, i - 1] matches p[0, j - 1] or not.
vector<vector<bool>> match(s_len + 1, vector<bool>(p_len + 1));
match[0][0] = true;
for (int i = 1; i <= p_len; ++i) {
if (p[i - 1] == '*') {
match[0][i] = match[0][i - 1];
}
}
for (int i = 1; i <= s_len; ++i) {
match[i][0] = false;
for (int j = 1; j <= p_len; ++j) {
if (p[j - 1] != '*') {
match[i][j] = match[i - 1][j - 1]
&& (s[i - 1] == p[j - 1] || p[j - 1] == '?');
}
else {
match[i][j] = match[i][j - 1] || match[i - 1][j];
}
}
}
return match[s_len][p_len];
}
};
// Time: O(m * n^2)
// Space: O(m + n)
// Recursion
class Solution_TLE {
public:
/**
* @param s: A string
* @param p: A string includes "?" and "*"
* @return: A boolean
*/
bool isMatch(const char *s, const char *p) {
if (*s == 0 || *p == 0) {
return *s == 0 && *p == 0;
}
if (p[0] != '*') {
if (p[0] == s[0] || p[0] == '?') {
// Matched a char.
return isMatch(s + 1, p + 1);
} else {
return false;
}
} else {
// Try all possible matches with '*' in p.
while (*s != 0) {
if (isMatch(s, p + 1)) {
return true;
}
++s;
}
return isMatch(s, p + 1);
}
}
};