101 Logo
onenoughtone

Solution Approach

Solution Overview

There are 2 main approaches to solve this problem:

  1. Recursive Approach - Complex approach
  2. Dynamic Programming Approach - Complex approach

Approach 1: Recursive Approach

We can solve this problem using recursion by breaking it down into smaller subproblems. At each step, we consider the current characters in both the text and pattern and make decisions based on what we encounter.

The key insight is to handle the '*' wildcard specially, as it can match zero or more characters. When we encounter a '*', we have two choices: either use it to match zero characters and move only in the pattern, or use it to match one or more characters by moving in the text.

Algorithm:

  1. Define a recursive function isMatch(text, pattern, i, j) where i and j are the current positions in the text and pattern.
  2. Base case: If we've reached the end of both text and pattern, return true.
  3. Base case: If we've reached the end of the pattern but not the text, return false.
  4. Base case: If we've reached the end of the text but not the pattern, return true only if all remaining characters in the pattern are '*'.
  5. If the current pattern character is '*':
  6. - Try matching zero characters: recursively call isMatch(text, pattern, i, j+1)
  7. - Try matching one or more characters: recursively call isMatch(text, pattern, i+1, j) if i < text.length
  8. - Return true if either of these recursive calls returns true.
  9. If the current pattern character is &apos;?&apos; or it matches the current text character:
  10. - Recursively call isMatch(text, pattern, i+1, j+1)
  11. Otherwise, return false.

Time Complexity:

O(2^(m+n))

where m is the length of the text and n is the length of the pattern. In the worst case, we might need to explore all possible combinations of matching.

Space Complexity:

O(m+n)

for the recursion stack. The maximum depth of recursion is bounded by the sum of the lengths of the text and pattern.

Approach 2: Dynamic Programming Approach

To optimize the recursive solution, we can use dynamic programming to avoid redundant calculations. We'll create a 2D DP table where dp[i][j] represents whether the first i characters of the text match the first j characters of the pattern.

Algorithm:

  1. Create a 2D boolean array dp of size (text.length+1) × (pattern.length+1).
  2. Initialize dp[0][0] = true (empty text matches empty pattern).
  3. For j from 1 to pattern.length:
  4. - If pattern[j-1] is &apos;*&apos;, set dp[0][j] = dp[0][j-1] (empty text can match pattern with &apos;*&apos;).
  5. For i from 1 to text.length and j from 1 to pattern.length:
  6. - If pattern[j-1] is &apos;*&apos;:
  7. * dp[i][j] = dp[i][j-1] (match zero characters) || dp[i-1][j] (match one or more characters)
  8. - If pattern[j-1] is &apos;?&apos; or pattern[j-1] equals text[i-1]:
  9. * dp[i][j] = dp[i-1][j-1]
  10. - Otherwise, dp[i][j] = false
  11. Return dp[text.length][pattern.length].

Time Complexity:

O(m×n)

where m is the length of the text and n is the length of the pattern. We fill a 2D table of size m×n.

Space Complexity:

O(m×n)

for the DP table. We need to store the result for each combination of text and pattern positions.

Pseudocode

solution.pseudo
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
function isMatch(text, pattern):
return recursiveMatch(text, pattern, 0, 0)
function recursiveMatch(text, pattern, i, j):
// Base cases
if j == pattern.length:
return i == text.length
if i == text.length:
// Remaining pattern must be all '*'
for k from j to pattern.length - 1:
if pattern[k] != '*':
return false
return true
// Current character in pattern
if pattern[j] == '*':
// Match zero characters
if recursiveMatch(text, pattern, i, j+1):
return true
// Match one or more characters
return recursiveMatch(text, pattern, i+1, j)
// Match single character
if pattern[j] == '?' or pattern[j] == text[i]:
return recursiveMatch(text, pattern, i+1, j+1)
return false
ProblemSolutionCode
101 Logo
onenoughtone