Skip to content

Commit 7674a84

Browse files
alxkmalxkmsiriak
authored
test: RegexMatchingTest (#5403)
* test: RegexMatchingTest * checkstyle: fix formatting --------- Co-authored-by: alxkm <[email protected]> Co-authored-by: Andrii Siriak <[email protected]>
1 parent 4374a50 commit 7674a84

File tree

2 files changed

+99
-23
lines changed

2 files changed

+99
-23
lines changed

src/main/java/com/thealgorithms/dynamicprogramming/RegexMatching.java

+56-23
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,28 @@
66
* cover the entire text ?-> matches single characters *-> match the sequence of
77
* characters
88
*
9-
* For calculation of Time and Space Complexity. Let N be length of src and M be
10-
* length of pat
9+
* For calculation of Time and Space Complexity. Let N be length of src and M be length of pat
1110
*
11+
* Memoization vs Tabulation : https://www.geeksforgeeks.org/tabulation-vs-memoization/
12+
* Question Link : https://practice.geeksforgeeks.org/problems/wildcard-pattern-matching/1
1213
*/
1314
public final class RegexMatching {
1415
private RegexMatching() {
1516
}
1617

17-
// Method 1: Using Recursion
18-
// Time Complexity=0(2^(N+M)) Space Complexity=Recursion Extra Space
19-
static boolean regexRecursion(String src, String pat) {
18+
/**
19+
* Method 1: Determines if the given source string matches the given pattern using a recursive approach.
20+
* This method directly applies recursion to check if the source string matches the pattern, considering
21+
* the wildcards '?' and '*'.
22+
*
23+
* Time Complexity: O(2^(N+M)), where N is the length of the source string and M is the length of the pattern.
24+
* Space Complexity: O(N + M) due to the recursion stack.
25+
*
26+
* @param src The source string to be matched against the pattern.
27+
* @param pat The pattern containing wildcards ('*' matches a sequence of characters, '?' matches a single character).
28+
* @return {@code true} if the source string matches the pattern, {@code false} otherwise.
29+
*/
30+
public static boolean regexRecursion(String src, String pat) {
2031
if (src.length() == 0 && pat.length() == 0) {
2132
return true;
2233
}
@@ -50,8 +61,19 @@ static boolean regexRecursion(String src, String pat) {
5061
return ans;
5162
}
5263

53-
// Method 2: Using Recursion and breaking string using virtual index
54-
// Time Complexity=0(2^(N+M)) Space Complexity=Recursion Extra Space
64+
/**
65+
* Method 2: Determines if the given source string matches the given pattern using recursion.
66+
* This method utilizes a virtual index for both the source string and the pattern to manage the recursion.
67+
*
68+
* Time Complexity: O(2^(N+M)) where N is the length of the source string and M is the length of the pattern.
69+
* Space Complexity: O(N + M) due to the recursion stack.
70+
*
71+
* @param src The source string to be matched against the pattern.
72+
* @param pat The pattern containing wildcards ('*' matches a sequence of characters, '?' matches a single character).
73+
* @param svidx The current index in the source string.
74+
* @param pvidx The current index in the pattern.
75+
* @return {@code true} if the source string matches the pattern, {@code false} otherwise.
76+
*/
5577
static boolean regexRecursion(String src, String pat, int svidx, int pvidx) {
5678
if (src.length() == svidx && pat.length() == pvidx) {
5779
return true;
@@ -83,9 +105,21 @@ static boolean regexRecursion(String src, String pat, int svidx, int pvidx) {
83105
return ans;
84106
}
85107

86-
// Method 3: Top-Down DP(Memoization)
87-
// Time Complexity=0(N*M) Space Complexity=0(N*M)+Recursion Extra Space
88-
static boolean regexRecursion(String src, String pat, int svidx, int pvidx, int[][] strg) {
108+
/**
109+
* Method 3: Determines if the given source string matches the given pattern using top-down dynamic programming (memoization).
110+
* This method utilizes memoization to store intermediate results, reducing redundant computations and improving efficiency.
111+
*
112+
* Time Complexity: O(N * M), where N is the length of the source string and M is the length of the pattern.
113+
* Space Complexity: O(N * M) for the memoization table, plus additional space for the recursion stack.
114+
*
115+
* @param src The source string to be matched against the pattern.
116+
* @param pat The pattern containing wildcards ('*' matches a sequence of characters, '?' matches a single character).
117+
* @param svidx The current index in the source string.
118+
* @param pvidx The current index in the pattern.
119+
* @param strg A 2D array used for memoization to store the results of subproblems.
120+
* @return {@code true} if the source string matches the pattern, {@code false} otherwise.
121+
*/
122+
public static boolean regexRecursion(String src, String pat, int svidx, int pvidx, int[][] strg) {
89123
if (src.length() == svidx && pat.length() == pvidx) {
90124
return true;
91125
}
@@ -120,8 +154,18 @@ static boolean regexRecursion(String src, String pat, int svidx, int pvidx, int[
120154
return ans;
121155
}
122156

123-
// Method 4: Bottom-Up DP(Tabulation)
124-
// Time Complexity=0(N*M) Space Complexity=0(N*M)
157+
/**
158+
* Method 4: Determines if the given source string matches the given pattern using bottom-up dynamic programming (tabulation).
159+
* This method builds a solution iteratively by filling out a table, where each cell represents whether a substring
160+
* of the source string matches a substring of the pattern.
161+
*
162+
* Time Complexity: O(N * M), where N is the length of the source string and M is the length of the pattern.
163+
* Space Complexity: O(N * M) for the table used in the tabulation process.
164+
*
165+
* @param src The source string to be matched against the pattern.
166+
* @param pat The pattern containing wildcards ('*' matches a sequence of characters, '?' matches a single character).
167+
* @return {@code true} if the source string matches the pattern, {@code false} otherwise.
168+
*/
125169
static boolean regexBU(String src, String pat) {
126170
boolean[][] strg = new boolean[src.length() + 1][pat.length() + 1];
127171
strg[src.length()][pat.length()] = true;
@@ -153,15 +197,4 @@ static boolean regexBU(String src, String pat) {
153197
}
154198
return strg[0][0];
155199
}
156-
157-
public static void main(String[] args) {
158-
String src = "aa";
159-
String pat = "*";
160-
System.out.println("Method 1: " + regexRecursion(src, pat));
161-
System.out.println("Method 2: " + regexRecursion(src, pat, 0, 0));
162-
System.out.println("Method 3: " + regexRecursion(src, pat, 0, 0, new int[src.length()][pat.length()]));
163-
System.out.println("Method 4: " + regexBU(src, pat));
164-
}
165200
}
166-
// Memoization vs Tabulation : https://www.geeksforgeeks.org/tabulation-vs-memoization/
167-
// Question Link : https://practice.geeksforgeeks.org/problems/wildcard-pattern-matching/1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package com.thealgorithms.dynamicprogramming;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
5+
import java.util.stream.Stream;
6+
import org.junit.jupiter.params.ParameterizedTest;
7+
import org.junit.jupiter.params.provider.Arguments;
8+
import org.junit.jupiter.params.provider.MethodSource;
9+
10+
public class RegexMatchingTest {
11+
12+
private record RegexTestCase(String s, String p, boolean expected) {
13+
}
14+
15+
private static Stream<Arguments> provideTestCases() {
16+
return Stream.of(Arguments.of(new RegexTestCase("aa", "*", true)), Arguments.of(new RegexTestCase("aa", "a*", true)), Arguments.of(new RegexTestCase("aa", "a", false)), Arguments.of(new RegexTestCase("cb", "?b", true)), Arguments.of(new RegexTestCase("cb", "?a", false)),
17+
Arguments.of(new RegexTestCase("adceb", "*a*b", true)), Arguments.of(new RegexTestCase("acdcb", "a*c?b", false)), Arguments.of(new RegexTestCase("", "*", true)), Arguments.of(new RegexTestCase("", "", true)));
18+
}
19+
20+
@ParameterizedTest
21+
@MethodSource("provideTestCases")
22+
void testRegexRecursionMethod1(RegexTestCase testCase) {
23+
assertEquals(testCase.expected(), RegexMatching.regexRecursion(testCase.s(), testCase.p()));
24+
}
25+
26+
@ParameterizedTest
27+
@MethodSource("provideTestCases")
28+
void testRegexRecursionMethod2(RegexTestCase testCase) {
29+
assertEquals(testCase.expected(), RegexMatching.regexRecursion(testCase.s(), testCase.p(), 0, 0));
30+
}
31+
32+
@ParameterizedTest
33+
@MethodSource("provideTestCases")
34+
void testRegexRecursionMethod3(RegexTestCase testCase) {
35+
assertEquals(testCase.expected(), RegexMatching.regexRecursion(testCase.s(), testCase.p(), 0, 0, new int[testCase.s().length()][testCase.p().length()]));
36+
}
37+
38+
@ParameterizedTest
39+
@MethodSource("provideTestCases")
40+
void testRegexBottomUp(RegexTestCase testCase) {
41+
assertEquals(testCase.expected(), RegexMatching.regexBU(testCase.s(), testCase.p()));
42+
}
43+
}

0 commit comments

Comments
 (0)