Skip to content

Commit 02df3ad

Browse files
committed
043
1 parent e0614bf commit 02df3ad

File tree

2 files changed

+107
-1
lines changed

2 files changed

+107
-1
lines changed

043 Wildcard Matching.py

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
"""
2+
Implement wildcard pattern matching with support for '?' and '*'.
3+
4+
'?' Matches any single character.
5+
'*' Matches any sequence of characters (including the empty sequence).
6+
7+
The matching should cover the entire input string (not partial).
8+
9+
The function prototype should be:
10+
bool isMatch(const char *s, const char *p)
11+
12+
Some examples:
13+
isMatch("aa","a") -> false
14+
isMatch("aa","aa") -> true
15+
isMatch("aaa","aa") -> false
16+
isMatch("aa", "*") -> true
17+
isMatch("aa", "a*") -> true
18+
isMatch("ab", "?*") -> true
19+
isMatch("aab", "c*a*b") -> false
20+
"""
21+
__author__ = 'Danyang'
22+
class Solution:
23+
def isMatch(self, s, p):
24+
"""
25+
dp, similar to 011 Regular Expression Matching.
26+
Backward dp
27+
28+
:param s: tape, an input string
29+
:param p: pattern, a pattern string
30+
:return: boolean
31+
"""
32+
tape = s
33+
pattern = p
34+
35+
m = len(tape)
36+
n = len(pattern)
37+
dp = [[False for _ in xrange(n+1)] for _ in xrange(m+1)]
38+
# edge cases
39+
dp[m][n] = True
40+
for j in xrange(n-1, -1 , -1):
41+
if pattern[j]=="*":
42+
dp[m][j] = dp[m][j+1]
43+
44+
# transition
45+
for i in xrange(m-1, -1, -1):
46+
for j in xrange(n-1, -1, -1):
47+
if tape[i]==pattern[j] or pattern[j]=="?":
48+
dp[i][j] = dp[i+1][j+1]
49+
elif pattern[j]=="*":
50+
dp[i][j] = dp[i][j+1] or dp[i+1][j] # zero or more
51+
else:
52+
dp[i][j] = False
53+
54+
55+
return dp[0][0]
56+
57+
def isMatch(self, s, p):
58+
"""
59+
Forward dp:
60+
dp starting from -1
61+
if pattern[j]!="*", dp[i][j] = dp[i-1][j-1] && tape[i] matches pattern[j]
62+
if pattern[j]=="*", dp[i][j] = any(dp[m][j-1])
63+
64+
Compact the 2-D dp to 1-D dp:
65+
iterate through j, since we only need know j-1 state, thus dropping the dimension for j in dp
66+
67+
:param s: tape, an input string
68+
:param p: pattern, a pattern string
69+
:return: boolean
70+
"""
71+
tape = s
72+
pattern = p
73+
74+
m = len(tape)
75+
n = len(pattern)
76+
77+
if n - list(pattern).count("*") > m:
78+
return False
79+
80+
dp = [False for _ in xrange(m+1)]
81+
dp[0] = True # dummy
82+
for j in xrange(1, n+1):
83+
if pattern[j-1]=="*":
84+
# for i in xrange(m, 0, -1):
85+
# dp[i] = any(dp[k] for k in xrange(i)) # Time Complexity
86+
k = 0
87+
while k<m+1 and dp[k]!=True: k+= 1
88+
for i in xrange(k, m+1):
89+
dp[i] = True
90+
else:
91+
for i in xrange(m, 0, -1):
92+
dp[i] = dp[i-1] and (tape[i-1]==pattern[j-1] or pattern[j-1]=="?")
93+
94+
dp[0] = dp[0] and pattern[j-1]=="*" # !!, pattern no longer match the empty string
95+
96+
97+
return dp[m]
98+
99+
if __name__=="__main__":
100+
assert Solution().isMatch("aab", "c*a*b")==False
101+
assert Solution().isMatch("aa","a")==False
102+
assert Solution().isMatch("aa", "aa")==True
103+
assert Solution().isMatch("aaa", "aa")==False
104+
assert Solution().isMatch("aaa", "*")==True
105+
assert Solution().isMatch("aa", "a*")==True
106+
assert Solution().isMatch("ab", "?*")==True

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Welcome to raise an issue if you have any feedback.
1212
Failed attempts are kept in the source code, which are annotated as TLE (Time Limit Exceeds) or MLE (Memory Limit Exceeds).
1313

1414
### TODO
15-
Question burn-down rate: 149/152 completed
15+
Question burn-down rate: 150/152 completed
1616

1717
[ascii](https://gist.github.com/xero/3555086)
1818
```

0 commit comments

Comments
 (0)