Skip to content

Commit 24ea996

Browse files
itsamirhntianyizheng02pre-commit-ci[bot]
authored andcommitted
Add: Two Regex match algorithm (Recursive & DP) (TheAlgorithms#6321)
* Add recursive solution to regex_match.py * Add dp solution to regex_match.py * Add link to regex_match.py * Minor edit * Minor change * Minor change * Update dynamic_programming/regex_match.py Co-authored-by: Tianyi Zheng <tianyizheng02@gmail.com> * Update dynamic_programming/regex_match.py Co-authored-by: Tianyi Zheng <tianyizheng02@gmail.com> * Fix ruff formatting in if statements * Update dynamic_programming/regex_match.py Co-authored-by: Tianyi Zheng <tianyizheng02@gmail.com> * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: Tianyi Zheng <tianyizheng02@gmail.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent dc36f62 commit 24ea996

File tree

1 file changed

+97
-0
lines changed

1 file changed

+97
-0
lines changed

dynamic_programming/regex_match.py

+97
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
"""
2+
Regex matching check if a text matches pattern or not.
3+
Pattern:
4+
'.' Matches any single character.
5+
'*' Matches zero or more of the preceding element.
6+
More info:
7+
https://medium.com/trick-the-interviwer/regular-expression-matching-9972eb74c03
8+
"""
9+
10+
11+
def recursive_match(text: str, pattern: str) -> bool:
12+
"""
13+
Recursive matching algorithm.
14+
15+
Time complexity: O(2 ^ (|text| + |pattern|))
16+
Space complexity: Recursion depth is O(|text| + |pattern|).
17+
18+
:param text: Text to match.
19+
:param pattern: Pattern to match.
20+
:return: True if text matches pattern, False otherwise.
21+
22+
>>> recursive_match('abc', 'a.c')
23+
True
24+
>>> recursive_match('abc', 'af*.c')
25+
True
26+
>>> recursive_match('abc', 'a.c*')
27+
True
28+
>>> recursive_match('abc', 'a.c*d')
29+
False
30+
>>> recursive_match('aa', '.*')
31+
True
32+
"""
33+
if not pattern:
34+
return not text
35+
36+
if not text:
37+
return pattern[-1] == "*" and recursive_match(text, pattern[:-2])
38+
39+
if text[-1] == pattern[-1] or pattern[-1] == ".":
40+
return recursive_match(text[:-1], pattern[:-1])
41+
42+
if pattern[-1] == "*":
43+
return recursive_match(text[:-1], pattern) or recursive_match(
44+
text, pattern[:-2]
45+
)
46+
47+
return False
48+
49+
50+
def dp_match(text: str, pattern: str) -> bool:
51+
"""
52+
Dynamic programming matching algorithm.
53+
54+
Time complexity: O(|text| * |pattern|)
55+
Space complexity: O(|text| * |pattern|)
56+
57+
:param text: Text to match.
58+
:param pattern: Pattern to match.
59+
:return: True if text matches pattern, False otherwise.
60+
61+
>>> dp_match('abc', 'a.c')
62+
True
63+
>>> dp_match('abc', 'af*.c')
64+
True
65+
>>> dp_match('abc', 'a.c*')
66+
True
67+
>>> dp_match('abc', 'a.c*d')
68+
False
69+
>>> dp_match('aa', '.*')
70+
True
71+
"""
72+
m = len(text)
73+
n = len(pattern)
74+
dp = [[False for _ in range(n + 1)] for _ in range(m + 1)]
75+
dp[0][0] = True
76+
77+
for j in range(1, n + 1):
78+
dp[0][j] = pattern[j - 1] == "*" and dp[0][j - 2]
79+
80+
for i in range(1, m + 1):
81+
for j in range(1, n + 1):
82+
if pattern[j - 1] in {".", text[i - 1]}:
83+
dp[i][j] = dp[i - 1][j - 1]
84+
elif pattern[j - 1] == "*":
85+
dp[i][j] = dp[i][j - 2]
86+
if pattern[j - 2] in {".", text[i - 1]}:
87+
dp[i][j] |= dp[i - 1][j]
88+
else:
89+
dp[i][j] = False
90+
91+
return dp[m][n]
92+
93+
94+
if __name__ == "__main__":
95+
import doctest
96+
97+
doctest.testmod()

0 commit comments

Comments
 (0)