test: RegexMatchingTest
(#5403)
* test: RegexMatchingTest * checkstyle: fix formatting --------- Co-authored-by: alxkm <alx@alx.com> Co-authored-by: Andrii Siriak <siryaka@gmail.com>
This commit is contained in:
parent
4374a50fd7
commit
7674a84f5b
@ -6,17 +6,28 @@ package com.thealgorithms.dynamicprogramming;
|
|||||||
* cover the entire text ?-> matches single characters *-> match the sequence of
|
* cover the entire text ?-> matches single characters *-> match the sequence of
|
||||||
* characters
|
* characters
|
||||||
*
|
*
|
||||||
* For calculation of Time and Space Complexity. Let N be length of src and M be
|
* For calculation of Time and Space Complexity. Let N be length of src and M be length of pat
|
||||||
* length of pat
|
|
||||||
*
|
*
|
||||||
|
* Memoization vs Tabulation : https://www.geeksforgeeks.org/tabulation-vs-memoization/
|
||||||
|
* Question Link : https://practice.geeksforgeeks.org/problems/wildcard-pattern-matching/1
|
||||||
*/
|
*/
|
||||||
public final class RegexMatching {
|
public final class RegexMatching {
|
||||||
private RegexMatching() {
|
private RegexMatching() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method 1: Using Recursion
|
/**
|
||||||
// Time Complexity=0(2^(N+M)) Space Complexity=Recursion Extra Space
|
* Method 1: Determines if the given source string matches the given pattern using a recursive approach.
|
||||||
static boolean regexRecursion(String src, String pat) {
|
* This method directly applies recursion to check if the source string matches the pattern, considering
|
||||||
|
* the wildcards '?' and '*'.
|
||||||
|
*
|
||||||
|
* Time Complexity: O(2^(N+M)), where N is the length of the source string and M is the length of the pattern.
|
||||||
|
* Space Complexity: O(N + M) due to the recursion stack.
|
||||||
|
*
|
||||||
|
* @param src The source string to be matched against the pattern.
|
||||||
|
* @param pat The pattern containing wildcards ('*' matches a sequence of characters, '?' matches a single character).
|
||||||
|
* @return {@code true} if the source string matches the pattern, {@code false} otherwise.
|
||||||
|
*/
|
||||||
|
public static boolean regexRecursion(String src, String pat) {
|
||||||
if (src.length() == 0 && pat.length() == 0) {
|
if (src.length() == 0 && pat.length() == 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -50,8 +61,19 @@ public final class RegexMatching {
|
|||||||
return ans;
|
return ans;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method 2: Using Recursion and breaking string using virtual index
|
/**
|
||||||
// Time Complexity=0(2^(N+M)) Space Complexity=Recursion Extra Space
|
* Method 2: Determines if the given source string matches the given pattern using recursion.
|
||||||
|
* This method utilizes a virtual index for both the source string and the pattern to manage the recursion.
|
||||||
|
*
|
||||||
|
* Time Complexity: O(2^(N+M)) where N is the length of the source string and M is the length of the pattern.
|
||||||
|
* Space Complexity: O(N + M) due to the recursion stack.
|
||||||
|
*
|
||||||
|
* @param src The source string to be matched against the pattern.
|
||||||
|
* @param pat The pattern containing wildcards ('*' matches a sequence of characters, '?' matches a single character).
|
||||||
|
* @param svidx The current index in the source string.
|
||||||
|
* @param pvidx The current index in the pattern.
|
||||||
|
* @return {@code true} if the source string matches the pattern, {@code false} otherwise.
|
||||||
|
*/
|
||||||
static boolean regexRecursion(String src, String pat, int svidx, int pvidx) {
|
static boolean regexRecursion(String src, String pat, int svidx, int pvidx) {
|
||||||
if (src.length() == svidx && pat.length() == pvidx) {
|
if (src.length() == svidx && pat.length() == pvidx) {
|
||||||
return true;
|
return true;
|
||||||
@ -83,9 +105,21 @@ public final class RegexMatching {
|
|||||||
return ans;
|
return ans;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method 3: Top-Down DP(Memoization)
|
/**
|
||||||
// Time Complexity=0(N*M) Space Complexity=0(N*M)+Recursion Extra Space
|
* Method 3: Determines if the given source string matches the given pattern using top-down dynamic programming (memoization).
|
||||||
static boolean regexRecursion(String src, String pat, int svidx, int pvidx, int[][] strg) {
|
* This method utilizes memoization to store intermediate results, reducing redundant computations and improving efficiency.
|
||||||
|
*
|
||||||
|
* Time Complexity: O(N * M), where N is the length of the source string and M is the length of the pattern.
|
||||||
|
* Space Complexity: O(N * M) for the memoization table, plus additional space for the recursion stack.
|
||||||
|
*
|
||||||
|
* @param src The source string to be matched against the pattern.
|
||||||
|
* @param pat The pattern containing wildcards ('*' matches a sequence of characters, '?' matches a single character).
|
||||||
|
* @param svidx The current index in the source string.
|
||||||
|
* @param pvidx The current index in the pattern.
|
||||||
|
* @param strg A 2D array used for memoization to store the results of subproblems.
|
||||||
|
* @return {@code true} if the source string matches the pattern, {@code false} otherwise.
|
||||||
|
*/
|
||||||
|
public static boolean regexRecursion(String src, String pat, int svidx, int pvidx, int[][] strg) {
|
||||||
if (src.length() == svidx && pat.length() == pvidx) {
|
if (src.length() == svidx && pat.length() == pvidx) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -120,8 +154,18 @@ public final class RegexMatching {
|
|||||||
return ans;
|
return ans;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method 4: Bottom-Up DP(Tabulation)
|
/**
|
||||||
// Time Complexity=0(N*M) Space Complexity=0(N*M)
|
* Method 4: Determines if the given source string matches the given pattern using bottom-up dynamic programming (tabulation).
|
||||||
|
* This method builds a solution iteratively by filling out a table, where each cell represents whether a substring
|
||||||
|
* of the source string matches a substring of the pattern.
|
||||||
|
*
|
||||||
|
* Time Complexity: O(N * M), where N is the length of the source string and M is the length of the pattern.
|
||||||
|
* Space Complexity: O(N * M) for the table used in the tabulation process.
|
||||||
|
*
|
||||||
|
* @param src The source string to be matched against the pattern.
|
||||||
|
* @param pat The pattern containing wildcards ('*' matches a sequence of characters, '?' matches a single character).
|
||||||
|
* @return {@code true} if the source string matches the pattern, {@code false} otherwise.
|
||||||
|
*/
|
||||||
static boolean regexBU(String src, String pat) {
|
static boolean regexBU(String src, String pat) {
|
||||||
boolean[][] strg = new boolean[src.length() + 1][pat.length() + 1];
|
boolean[][] strg = new boolean[src.length() + 1][pat.length() + 1];
|
||||||
strg[src.length()][pat.length()] = true;
|
strg[src.length()][pat.length()] = true;
|
||||||
@ -153,15 +197,4 @@ public final class RegexMatching {
|
|||||||
}
|
}
|
||||||
return strg[0][0];
|
return strg[0][0];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
String src = "aa";
|
|
||||||
String pat = "*";
|
|
||||||
System.out.println("Method 1: " + regexRecursion(src, pat));
|
|
||||||
System.out.println("Method 2: " + regexRecursion(src, pat, 0, 0));
|
|
||||||
System.out.println("Method 3: " + regexRecursion(src, pat, 0, 0, new int[src.length()][pat.length()]));
|
|
||||||
System.out.println("Method 4: " + regexBU(src, pat));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Memoization vs Tabulation : https://www.geeksforgeeks.org/tabulation-vs-memoization/
|
|
||||||
// Question Link : https://practice.geeksforgeeks.org/problems/wildcard-pattern-matching/1
|
|
||||||
|
@ -0,0 +1,43 @@
|
|||||||
|
package com.thealgorithms.dynamicprogramming;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.Arguments;
|
||||||
|
import org.junit.jupiter.params.provider.MethodSource;
|
||||||
|
|
||||||
|
public class RegexMatchingTest {
|
||||||
|
|
||||||
|
private record RegexTestCase(String s, String p, boolean expected) {
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Stream<Arguments> provideTestCases() {
|
||||||
|
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)),
|
||||||
|
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)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("provideTestCases")
|
||||||
|
void testRegexRecursionMethod1(RegexTestCase testCase) {
|
||||||
|
assertEquals(testCase.expected(), RegexMatching.regexRecursion(testCase.s(), testCase.p()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("provideTestCases")
|
||||||
|
void testRegexRecursionMethod2(RegexTestCase testCase) {
|
||||||
|
assertEquals(testCase.expected(), RegexMatching.regexRecursion(testCase.s(), testCase.p(), 0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("provideTestCases")
|
||||||
|
void testRegexRecursionMethod3(RegexTestCase testCase) {
|
||||||
|
assertEquals(testCase.expected(), RegexMatching.regexRecursion(testCase.s(), testCase.p(), 0, 0, new int[testCase.s().length()][testCase.p().length()]));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("provideTestCases")
|
||||||
|
void testRegexBottomUp(RegexTestCase testCase) {
|
||||||
|
assertEquals(testCase.expected(), RegexMatching.regexBU(testCase.s(), testCase.p()));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user