Check if a given pattern exists in a given string or not - GeeksforGeeks

11 Jun, 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]).
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]).
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++
Java
Python3
C#
Javascript
// 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 notint 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 Codeint 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 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 program for the above approachimport numpy as np # Function to check if the pattern# consisting of '*', '.' and lowercase# characters matches the text or notdef 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 Codeif __name__ == "__main__" :   text = "geeksforgeeks"  pattern = "ge*ksforgeeks"     if (isMatch(text, pattern)):    print("Yes")  else:    print("No") # This code is contributed by AnkThon
// C# program for the above approachusing System; class GFG{ // Function to check if the pattern// consisting of '*', '.' and lowercase// characters matches the text or notstatic 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 Codepublic 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
<script>     // JavaScript program for the above approach         // Function to check if the pattern    // consisting of '*', '.' and lowercase    // characters matches the text or not    function isMatch(text, pattern)    {        // Base Case        if (text == null || pattern == null) {            return false;        }          // Stores length of text        let N = text.length;          // Stores length of pattern        let M = pattern.length;          // dp[i][j]: Check if { text[0], .. text[i] }        // matches {pattern[0], ... pattern[j]} or not        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;            }        }                   // Base Case        dp[0][0] = true;          // Iterate over the characters        // of the string pattern        for (let 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 (let i = 0; i < N; i++) {              for (let 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];    }         let text = "geeksforgeeks";    let pattern = "ge*ksforgeeks";     if (isMatch(text, pattern)) {      document.write("Yes");    }    else {      document.write("No");    } </script>
Yes
 
Time Complexity: O(M * N)Auxiliary Space: O(M * N)
mohit kumar 29
ukasp
ankthon
divyeshrabadiya07
regular-expression
Technical Scripter 2020
Dynamic Programming
Pattern Searching
Recursion
Strings
Technical Scripter
Strings
Dynamic Programming
Recursion
Pattern Searching
Writing code in comment?
Please use ide.geeksforgeeks.org,
generate link and share the link here.
Optimal Substructure Property in Dynamic Programming | DP-2
Min Cost Path | DP-6
Count All Palindrome Sub-Strings in a String | Set 1
Maximum sum such that no two elements are adjacent
Optimal Strategy for a Game | DP-31
KMP Algorithm for Pattern Searching
Rabin-Karp Algorithm for Pattern Searching
Naive algorithm for Pattern Searching
Check if a string is substring of another
Boyer Moore Algorithm for Pattern Searching