Given two strings text and pattern of length M and N respectively, The task is to check if the pattern matches the text or not. If found to be true, then print “Yes”. Otherwise, print “No”.
Note: pattern can include the characters ‘*’ and ‘•’
- ‘*’ matches zero or more occurrences of character right before the current character
- ‘•’ matches any signal character.
Examples:
Input: pattern = “ge*ksforgeeks”, text = “geeksforgeeks”
Output: Yes
Explanation:
Replacing ‘*’ with ‘e’, modifies pattern equal to “geeksforgeeks”.
Therefore, the required output is Yes.
Input: pattern = “ab*d”, text = “abcds”
Output: No
Explanation: The given pattern cannot be matched with the text.
Naive Approach: Below is the idea to solve the problem:
The simplest approach to solve this problem is to iterate over the characters of the both the strings using recursion. If current character is ‘.’, replace current character to any character and recur for the remaining pattern and text string. Otherwise, if the current character is ‘*’, recur for the remaining text and check if it matches the rest of the pattern or not. If found to be true, then print “Yes”. Otherwise, print “No”.
Time Complexity: O((M + N) * 2(M + N / 2?))
Auxiliary Space: O((M + N) * 2(M + N / 2?))
Check if a given pattern exists in a given string or not using Dynamic Programming
Below is the idea to solve the problem:
Construct a 2D array dp[M+1][N+1] with DP state dp[i][j] denoting if the first i characters of string text match with the first j characters of pattern then assign dp[i][j] as 1 else 0 according to the match of text[i] and pattern[j] and true value of dp[i-1][j-1].
- Initialize a 2D array, dp[M + 1][N + 1], where dp[i][j] check if the substring {text[0], …, text[i]} matches with the substring {pattern[0], … pattern[j]} or not.
- Iterate over the characters of the both the strings and fill the dp[][] array based on the following recurrence relation:
- If text[i] and pattern[j] are the same then characters match so fill dp[i + 1][j + 1] = dp[i][j].
- If pattern[j] is ‘.’ then characters match so fill dp[i + 1][j + 1] = dp[i][j].
- If pattern[j] is ‘*’ then check the following conditions:
- If text[i] is not equal to pattern[j – 1] and pattern[j – 1] is not equal to ‘.’, then characters don’t match so fill dp[i + 1][j + 1] = dp[i + 1][j – 1].
- Otherwise, fill dp[i + 1][j + 1] = (dp[i + 1][j] || dp[i][j + 1] || dp[i + 1][j – 1]).
- Finally, print the value of dp[M][N].
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
int isMatch(string text, string pattern)
{
if (text == "" or pattern == "" )
return false ;
int N = text.size();
int M = pattern.size();
vector<vector< bool > > dp(N + 1,
vector< bool >(M + 1, false ));
dp[0][0] = true ;
for ( int i = 0; i < M; i++) {
if (pattern[i] == '*' && dp[0][i - 1]) {
dp[0][i + 1] = true ;
}
}
for ( int i = 0; i < N; i++) {
for ( int j = 0; j < M; j++) {
if (pattern[j] == '.' ) {
dp[i + 1][j + 1] = dp[i][j];
}
if (pattern[j] == text[i]) {
dp[i + 1][j + 1] = dp[i][j];
}
if (pattern[j] == '*' ) {
if (pattern[j - 1] != text[i]
&& pattern[j - 1] != '.' ) {
dp[i + 1][j + 1] = dp[i + 1][j - 1];
}
else {
dp[i + 1][j + 1]
= (dp[i + 1][j] or dp[i][j + 1]
or dp[i + 1][j - 1]);
}
}
}
}
return dp[N][M];
}
int main()
{
string text = "geeksforgeeks" ;
string pattern = "ge*ksforgeeks" ;
if (isMatch(text, pattern))
cout << "Yes" ;
else
cout << "No" ;
}
|
Java
import java.io.*;
class GFG {
static boolean isMatch(String text, String pattern)
{
if (text == null || pattern == null ) {
return false ;
}
int N = text.length();
int M = pattern.length();
boolean [][] dp = new boolean [N + 1 ][M + 1 ];
dp[ 0 ][ 0 ] = true ;
for ( int i = 0 ; i < M; i++) {
if (pattern.charAt(i) == '*' && dp[ 0 ][i - 1 ]) {
dp[ 0 ][i + 1 ] = true ;
}
}
for ( int i = 0 ; i < N; i++) {
for ( int j = 0 ; j < M; j++) {
if (pattern.charAt(j) == '.' ) {
dp[i + 1 ][j + 1 ] = dp[i][j];
}
if (pattern.charAt(j) == text.charAt(i)) {
dp[i + 1 ][j + 1 ] = dp[i][j];
}
if (pattern.charAt(j) == '*' ) {
if (pattern.charAt(j - 1 )
!= text.charAt(i)
&& pattern.charAt(j - 1 ) != '.' ) {
dp[i + 1 ][j + 1 ] = dp[i + 1 ][j - 1 ];
}
else {
dp[i + 1 ][j + 1 ]
= (dp[i + 1 ][j] || dp[i][j + 1 ]
|| dp[i + 1 ][j - 1 ]);
}
}
}
}
return dp[N][M];
}
public static void main(String[] args)
{
String text = "geeksforgeeks" ;
String pattern = "ge*ksforgeeks" ;
if (isMatch(text, pattern)) {
System.out.println( "Yes" );
}
else {
System.out.println( "No" );
}
}
}
|
Python3
def isMatch(text, pattern):
if (text = = " " or pattern == " "):
return False
N = len (text)
M = len (pattern)
rows, cols = (N + 1 , M + 1 )
dp = [[ 0 ] * cols] * rows
dp[ 0 ][ 0 ] = True
for i in range (M):
if (pattern[i] = = '*' and dp[ 0 ][i - 1 ]):
dp[ 0 ][i + 1 ] = True
for i in range (N):
for j in range (M):
if (pattern[j] = = '.' ):
dp[i + 1 ][j + 1 ] = dp[i][j]
if (pattern[j] = = text[i]):
dp[i + 1 ][j + 1 ] = dp[i][j]
if (pattern[j] = = '*' ):
if (pattern[j - 1 ] ! = text[i] and
pattern[j - 1 ] ! = '.' ):
dp[i + 1 ][j + 1 ] = dp[i + 1 ][j - 1 ]
else :
dp[i + 1 ][j + 1 ] = (dp[i + 1 ][j] or
dp[i][j + 1 ] or
dp[i + 1 ][j - 1 ])
return dp[N][M]
if __name__ = = "__main__" :
text = "geeksforgeeks"
pattern = "ge*ksforgeeks"
if (isMatch(text, pattern)):
print ( "Yes" )
else :
print ( "No" )
|
Javascript
<script>
function isMatch(text, pattern)
{
if (text == null || pattern == null ) {
return false ;
}
let N = text.length;
let M = pattern.length;
let dp = new Array(N + 1);
for (let i = 0; i <= N; i++)
{
dp[i] = new Array(M + 1);
for (let j = 0; j <= M; j++)
{
dp[i][j] = false ;
}
}
dp[0][0] = true ;
for (let i = 0; i < M; i++) {
if (pattern[i] == '*'
&& dp[0][i - 1]) {
dp[0][i + 1] = true ;
}
}
for (let i = 0; i < N; i++) {
for (let j = 0; j < M; j++) {
if (pattern[j] == '.' ) {
dp[i + 1][j + 1] = dp[i][j];
}
if (pattern[j] == text[i]) {
dp[i + 1][j + 1] = dp[i][j];
}
if (pattern[j] == '*' ) {
if (pattern[j - 1] != text[i]
&& pattern[j - 1] != '.' ) {
dp[i + 1][j + 1] = dp[i + 1][j - 1];
}
else {
dp[i + 1][j + 1] = (dp[i + 1][j]
|| dp[i][j + 1]
|| dp[i + 1][j - 1]);
}
}
}
}
return dp[N][M];
}
let text = "geeksforgeeks" ;
let pattern = "ge*ksforgeeks" ;
if (isMatch(text, pattern)) {
document.write( "Yes" );
}
else {
document.write( "No" );
}
</script>
|
C#
using System;
class GFG {
static bool isMatch( string text, string pattern)
{
if (text == null || pattern == null ) {
return false ;
}
int N = text.Length;
int M = pattern.Length;
bool [, ] dp = new bool [N + 1, M + 1];
dp[0, 0] = true ;
for ( int i = 0; i < M; i++) {
if (pattern[i] == '*' && dp[0, i - 1]) {
dp[0, i + 1] = true ;
}
}
for ( int i = 0; i < N; i++) {
for ( int j = 0; j < M; j++) {
if (pattern[j] == '.' ) {
dp[i + 1, j + 1] = dp[i, j];
}
if (pattern[j] == text[i]) {
dp[i + 1, j + 1] = dp[i, j];
}
if (pattern[j] == '*' ) {
if (pattern[j - 1] != text[i]
&& pattern[j - 1] != '.' ) {
dp[i + 1, j + 1] = dp[i + 1, j - 1];
}
else {
dp[i + 1, j + 1]
= (dp[i + 1, j] || dp[i, j + 1]
|| dp[i + 1, j - 1]);
}
}
}
}
return dp[N, M];
}
public static void Main()
{
string text = "geeksforgeeks" ;
string pattern = "ge*ksforgeeks" ;
if (isMatch(text, pattern)) {
Console.WriteLine( "Yes" );
}
else {
Console.WriteLine( "No" );
}
}
}
|
Time Complexity: O(M * N)
Auxiliary Space: O(M * N)
Efficient Approach : using array instead of 2d matrix to optimize space complexity
In previous code we can se that dp[i][j] is dependent upon dp[i+1][j-1] or dp[i][j-1] so we can assume that dp[i+1] is current row and dp[i] is previous row.
Implementations Steps :
- Initialize a 1D boolean vector ‘dp’ of size M+1, where M is the length of the pattern.
- Base case: dp[0] is true, as an empty pattern matches an empty text.
- Iterate over the characters of the pattern. If the current character is ‘*’, update dp[i+1] to true if dp[i-1] is true.
- Iterate over the characters of the text. Keep a variable ‘prev’ to store the previous value of dp[j]. For each character in the pattern, update dp[j+1] based on the current and previous values of dp[j], dp[j-1], and prev, depending on the character in the pattern.
- Return dp[M] as the final answer. If dp[M] is true, the pattern matches the text; otherwise, it does not.
Implementation :
C++
#include <bits/stdc++.h>
using namespace std;
int isMatch(string text, string pattern)
{
if (text == "" or pattern == "" )
return false ;
int N = text.size();
int M = pattern.size();
vector< bool > dp(M + 1, false );
dp[0] = true ;
for ( int i = 0; i < M; i++) {
if (pattern[i] == '*' && dp[i - 1]) {
dp[i + 1] = true ;
}
}
for ( int i = 0; i < N; i++) {
bool prev = dp[0];
dp[0] = false ;
for ( int j = 0; j < M; j++) {
bool temp = dp[j+1];
if (pattern[j] == '.' ) {
dp[j + 1] = prev;
}
else if (pattern[j] == text[i]) {
dp[j + 1] = prev;
}
else if (pattern[j] == '*' ) {
if (pattern[j - 1] != text[i]
&& pattern[j - 1] != '.' ) {
dp[j + 1] = dp[j - 1];
}
else {
dp[j + 1] = (dp[j + 1] or dp[j] or prev);
}
}
else {
dp[j + 1] = false ;
}
prev = temp;
}
}
return dp[M];
}
int main()
{
string text = "geeksforgeeks" ;
string pattern = "ge*ksforgeeks" ;
if (isMatch(text, pattern))
cout << "Yes" ;
else
cout << "No" ;
}
|
Java
import java.util.*;
public class Main {
static int isMatch(String text, String pattern)
{
if (text.equals( "" ) || pattern.equals( "" ))
return 0 ;
int N = text.length();
int M = pattern.length();
boolean [] dp = new boolean [M + 1 ];
dp[ 0 ] = true ;
for ( int i = 0 ; i < M; i++) {
if (pattern.charAt(i) == '*' && dp[i - 1 ]) {
dp[i + 1 ] = true ;
}
}
for ( int i = 0 ; i < N; i++) {
boolean prev = dp[ 0 ];
dp[ 0 ] = false ;
for ( int j = 0 ; j < M; j++) {
boolean temp = dp[j + 1 ];
if (pattern.charAt(j) == '.' ) {
dp[j + 1 ] = prev;
}
else if (pattern.charAt(j)
== text.charAt(i)) {
dp[j + 1 ] = prev;
}
else if (pattern.charAt(j) == '*' ) {
if (j > 0
&& pattern.charAt(j - 1 )
!= text.charAt(i)
&& pattern.charAt(j - 1 ) != '.' ) {
dp[j + 1 ] = dp[j - 1 ];
}
else {
dp[j + 1 ]
= (dp[j + 1 ] || dp[j] || prev);
}
}
else {
dp[j + 1 ] = false ;
}
prev = temp;
}
}
return dp[M] ? 1 : 0 ;
}
public static void main(String[] args)
{
String text = "geeksforgeeks" ;
String pattern = "ge*ksforgeeks" ;
if (isMatch(text, pattern) == 1 )
System.out.println( "Yes" );
else
System.out.println( "No" );
}
}
|
Python3
def isMatch(text, pattern):
if text = = " " or pattern == " ":
return False
N = len (text)
M = len (pattern)
dp = [ False ] * (M + 1 )
dp[ 0 ] = True
for i in range (M):
if pattern[i] = = '*' and dp[i - 1 ]:
dp[i + 1 ] = True
for i in range (N):
prev = dp[ 0 ]
dp[ 0 ] = False
for j in range (M):
temp = dp[j + 1 ]
if pattern[j] = = '.' :
dp[j + 1 ] = prev
elif pattern[j] = = text[i]:
dp[j + 1 ] = prev
elif pattern[j] = = '*' :
if pattern[j - 1 ] ! = text[i] and pattern[j - 1 ] ! = '.' :
dp[j + 1 ] = dp[j - 1 ]
else :
dp[j + 1 ] = (dp[j + 1 ] or dp[j] or prev)
else :
dp[j + 1 ] = False
prev = temp
return dp[M]
if __name__ = = '__main__' :
text = "geeksforgeeks"
pattern = "ge*ksforgeeks"
if isMatch(text, pattern):
print ( "Yes" )
else :
print ( "No" )
|
Javascript
function isMatch(text, pattern) {
if (text === "" || pattern === "" ) {
return false ;
}
let N = text.length;
let M = pattern.length;
let dp = new Array(M + 1).fill( false );
dp[0] = true ;
for (let i = 0; i < M; i++) {
if (pattern[i] === '*' && dp[i - 1]) {
dp[i + 1] = true ;
}
}
for (let i = 0; i < N; i++) {
let prev = dp[0];
dp[0] = false ;
for (let j = 0; j < M; j++) {
let temp = dp[j+1];
if (pattern[j] === '.' ) {
dp[j + 1] = prev;
}
else if (pattern[j] === text[i]) {
dp[j + 1] = prev;
}
else if (pattern[j] === '*' ) {
if (pattern[j - 1] !== text[i]
&& pattern[j - 1] !== '.' ) {
dp[j + 1] = dp[j - 1];
}
else {
dp[j + 1] = (dp[j + 1] || dp[j] || prev);
}
}
else {
dp[j + 1] = false ;
}
prev = temp;
}
}
return dp[M];
}
let text = "geeksforgeeks" ;
let pattern = "ge*ksforgeeks" ;
if (isMatch(text, pattern)) {
console.log( "Yes" );
} else {
console.log( "No" );
}
|
C#
using System;
class GFG {
static bool isMatch( string text, string pattern)
{
if (text == "" || pattern == "" ) {
return false ;
}
int N = text.Length;
int M = pattern.Length;
bool [] dp = new bool [M + 1];
dp[0] = true ;
for ( int i = 0; i < M; i++) {
if (pattern[i] == '*' && dp[i - 1]) {
dp[i + 1] = true ;
}
}
for ( int i = 0; i < N; i++) {
bool prev = dp[0];
dp[0] = false ;
for ( int j = 0; j < M; j++) {
bool temp = dp[j + 1];
if (pattern[j] == '.' ) {
dp[j + 1] = prev;
}
else if (pattern[j] == text[i]) {
dp[j + 1] = prev;
}
else if (pattern[j] == '*' ) {
if (pattern[j - 1] != text[i]
&& pattern[j - 1] != '.' ) {
dp[j + 1] = dp[j - 1];
}
else {
dp[j + 1]
= (dp[j + 1] || dp[j] || prev);
}
}
else {
dp[j + 1] = false ;
}
prev = temp;
}
}
return dp[M];
}
static void Main( string [] args)
{
string text = "geeksforgeeks" ;
string pattern = "ge*ksforgeeks" ;
if (isMatch(text, pattern)) {
Console.WriteLine( "Yes" );
}
else {
Console.WriteLine( "No" );
}
}
}
|
Time Complexity: O(M * N), where N is the size of the text string and M is the size of the pattern string
Auxiliary Space: O(M)1, space used for storing DP values