Skip to content
Related Articles

Related Articles

Check if a given pattern exists in a given string or not
  • Difficulty Level : Hard
  • Last Updated : 15 Apr, 2021

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: 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​))

Efficient Approach: The above approach can be optimized using Dynamic Programming. Following are the recurrence relation: 

  • Initialize a 2D array, dp[M + 1][N + 1], where dp[i][j] check if the substring { text[0], …, text[i] } is 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 fill dp[i + 1][j + 1] = dp[i][j].
    • If pattern[j] is ‘.’ then 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 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++




// C++ program for the above approach
#include <bits/stdc++.h>
using namespace std;
 
// Function to check if the pattern
// consisting of '*', '.' and lowercase
// characters matches the text or not
int isMatch(string text, string pattern)
{
 
  // Base Case
  if (text == "" or pattern == "")
    return false;
 
  // Stores length of text
  int N = text.size();
 
  // Stores length of pattern
  int M = pattern.size();
 
  // dp[i][j]: Check if { text[0], .. text[i] }
  // matches {pattern[0], ... pattern[j]} or not
  vector<vector<bool>> dp(N + 1, vector<bool>(M + 1, false));
 
  // Base Case
  dp[0][0] = true;
 
  // Iterate over the characters
  // of the string pattern
  for (int i = 0; i < M; i++)
  {
    if (pattern[i] == '*'
        && dp[0][i - 1]) {
 
      // Update dp[0][i + 1]
      dp[0][i + 1] = true;
    }
  }
 
  // Iterate over the characters
  // of both the strings
  for (int i = 0; i < N; i++) {
 
    for (int j = 0; j < M; j++) {
 
      // If current character
      // in the pattern is '.'
      if (pattern[j] == '.') {
 
        // Update dp[i + 1][j + 1]
        dp[i + 1][j + 1] = dp[i][j];
      }
 
      // If current character in
      // both the strings are equal
      if (pattern[j]
          == text[i]) {
 
        // Update dp[i + 1][j + 1]
        dp[i + 1][j + 1] = dp[i][j];
      }
 
      // If current character
      // in the pattern is '*'
      if (pattern[j] == '*') {
 
        if (pattern[j - 1] != text[i]
            && pattern[j - 1] != '.') {
 
          // Update dp[i + 1][j + 1]
          dp[i + 1][j + 1] = dp[i + 1][j - 1];
        }
 
        else {
 
          // Update dp[i+1][j+1]
          dp[i + 1][j + 1] = (dp[i + 1][j]
                              or dp[i][j + 1]
                              or dp[i + 1][j - 1]);
        }
      }
    }
  }
 
  // Return dp[M][N]
  return dp[N][M];
}
 
// Driver Code
int main()
{
  string text = "geeksforgeeks";
  string pattern = "ge*ksforgeeks";
 
  if (isMatch(text, pattern))
    cout<<"Yes";
  else
    cout<<"No";
}
 
// This code is contributed by mohiy kumar 29.

Java




// Java program for the above approach
 
import java.io.*;
 
class GFG {
 
    // Function to check if the pattern
    // consisting of '*', '.' and lowercase
    // characters matches the text or not
    static boolean isMatch(String text,
                           String pattern)
    {
        // Base Case
        if (text == null || pattern == null) {
            return false;
        }
 
        // Stores length of text
        int N = text.length();
 
        // Stores length of pattern
        int M = pattern.length();
 
        // dp[i][j]: Check if { text[0], .. text[i] }
        // matches {pattern[0], ... pattern[j]} or not
        boolean[][] dp = new boolean[N + 1][M + 1];
 
        // Base Case
        dp[0][0] = true;
 
        // Iterate over the characters
        // of the string pattern
        for (int i = 0; i < M; i++) {
            if (pattern.charAt(i) == '*'
                && dp[0][i - 1]) {
 
                // Update dp[0][i + 1]
                dp[0][i + 1] = true;
            }
        }
 
        // Iterate over the characters
        // of both the strings
        for (int i = 0; i < N; i++) {
 
            for (int j = 0; j < M; j++) {
 
                // If current character
                // in the pattern is '.'
                if (pattern.charAt(j) == '.') {
 
                    // Update dp[i + 1][j + 1]
                    dp[i + 1][j + 1] = dp[i][j];
                }
 
                // If current character in
                // both the strings are equal
                if (pattern.charAt(j)
                    == text.charAt(i)) {
 
                    // Update dp[i + 1][j + 1]
                    dp[i + 1][j + 1] = dp[i][j];
                }
 
                // If current character
                // in the pattern is '*'
                if (pattern.charAt(j) == '*') {
 
                    if (pattern.charAt(j - 1) != text.charAt(i)
                        && pattern.charAt(j - 1) != '.') {
 
                        // Update dp[i + 1][j + 1]
                        dp[i + 1][j + 1] = dp[i + 1][j - 1];
                    }
 
                    else {
 
                        // Update dp[i+1][j+1]
                        dp[i + 1][j + 1] = (dp[i + 1][j]
                                            || dp[i][j + 1]
                                            || dp[i + 1][j - 1]);
                    }
                }
            }
        }
 
        // Return dp[M][N]
        return dp[N][M];
    }
 
    // Driver Code
    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




# Python3 program for the above approach
import numpy as np
 
# Function to check if the pattern
# consisting of '*', '.' and lowercase
# characters matches the text or not
def isMatch(text, pattern):
     
  # Base Case
  if (text == "" or pattern == ""):
    return False
 
  # Stores length of text
  N = len(text)
 
  # Stores length of pattern
  M = len(pattern)
 
  # dp[i][j]: Check if { text[0], .. text[i] }
  # matches {pattern[0], ... pattern[j]} or not
  dp = np.zeros((N + 1, M + 1))
 
  # Base Case
  dp[0][0] = True
 
  # Iterate over the characters
  # of the string pattern
  for i in range(M):
    if (pattern[i] == '*' and dp[0][i - 1]):
 
      # Update dp[0][i + 1]
      dp[0][i + 1] = True
 
  # Iterate over the characters
  # of both the strings
  for i in range(N):
    for j in range(M):
 
      # If current character
      # in the pattern is '.'
      if (pattern[j] == '.'):
 
        # Update dp[i + 1][j + 1]
        dp[i + 1][j + 1] = dp[i][j]
 
      # If current character in
      # both the strings are equal
      if (pattern[j] == text[i]):
 
        # Update dp[i + 1][j + 1]
        dp[i + 1][j + 1] = dp[i][j]
 
      # If current character
      # in the pattern is '*'
      if (pattern[j] == '*'):
        if (pattern[j - 1] != text[i] and
            pattern[j - 1] != '.'):
 
          # Update dp[i + 1][j + 1]
          dp[i + 1][j + 1] = dp[i + 1][j - 1]
         
        else:
 
          # Update dp[i+1][j+1]
          dp[i + 1][j + 1] = (dp[i + 1][j] or
                              dp[i][j + 1] or
                              dp[i + 1][j - 1])
 
  # Return dp[M][N]
  return dp[N][M]
 
# Driver Code
if __name__ == "__main__" :
 
  text = "geeksforgeeks"
  pattern = "ge*ksforgeeks"
   
  if (isMatch(text, pattern)):
    print("Yes")
  else:
    print("No")
 
# This code is contributed by AnkThon

C#




// C# program for the above approach
using System;
 
class GFG{
 
// Function to check if the pattern
// consisting of '*', '.' and lowercase
// characters matches the text or not
static bool isMatch(string text, string pattern)
{
     
    // Base Case
    if (text == null || pattern == null)
    {
        return false;
    }
 
    // Stores length of text
    int N = text.Length;
 
    // Stores length of pattern
    int M = pattern.Length;
 
    // dp[i][j]: Check if { text[0], .. text[i] }
    // matches {pattern[0], ... pattern[j]} or not
    bool[,] dp = new bool[N + 1, M + 1];
 
    // Base Case
    dp[0, 0] = true;
 
    // Iterate over the characters
    // of the string pattern
    for(int i = 0; i < M; i++)
    {
        if (pattern[i] == '*' && dp[0, i - 1])
        {
             
            // Update dp[0][i + 1]
            dp[0, i + 1] = true;
        }
    }
 
    // Iterate over the characters
    // of both the strings
    for(int i = 0; i < N; i++)
    {
        for(int j = 0; j < M; j++)
        {
             
            // If current character
            // in the pattern is '.'
            if (pattern[j] == '.')
            {
                 
                // Update dp[i + 1][j + 1]
                dp[i + 1, j + 1] = dp[i, j];
            }
 
            // If current character in
            // both the strings are equal
            if (pattern[j] == text[i])
            {
                 
                // Update dp[i + 1][j + 1]
                dp[i + 1, j + 1] = dp[i, j];
            }
 
            // If current character
            // in the pattern is '*'
            if (pattern[j] == '*')
            {
                if (pattern[j - 1] != text[i] &&
                    pattern[j - 1] != '.')
                {
                     
                    // Update dp[i + 1][j + 1]
                    dp[i + 1, j + 1] = dp[i + 1, j - 1];
                }
 
                else
                {
                     
                    // Update dp[i+1][j+1]
                    dp[i + 1, j + 1] = (dp[i + 1, j] ||
                                        dp[i, j + 1] ||
                                        dp[i + 1, j - 1]);
                }
            }
        }
    }
 
    // Return dp[M][N]
    return dp[N, M];
}
 
// Driver Code
public static void Main()
{
    string text = "geeksforgeeks";
    string pattern = "ge*ksforgeeks";
 
    if (isMatch(text, pattern))
    {
        Console.WriteLine("Yes");
    }
    else
    {
        Console.WriteLine("No");
    }
}
}
 
// This code is contributed by ukasp
Output: 
Yes

 

Time Complexity: O(M * N)
Auxiliary Space: O(M * N)

My Personal Notes arrow_drop_up
Recommended Articles
Page :