Given a text and a wildcard pattern, implement wildcard pattern matching algorithm that finds if wildcard pattern is matched with text. The matching should cover the entire text (not partial text). The wildcard pattern can include the characters ‘?’, ‘*’ and ‘+’.
‘?’ – matches any single character ‘*’ – Matches any sequence of characters (including the empty sequence) '+' – Matches previous single character of pattern
Examples:
Input :Text = "baaabaaa", Pattern = “****+ba*****a+", output : true Pattern = "baaa?ab", output : false Pattern = "ba*a?", output : true Pattern = "+a*ab", output : false Input : Text = "aab" Pattern = "*+" output : false Pattern = "*+b" output : true
- Case 1: The character is ‘*’ Here two cases arise: We can ignore ‘*’ character and move to next character in the pattern. ‘*’ character matches with one or more characters in text. Here we will move to next character in the string.
- Case 2: The character is ‘?’ We can ignore current character in text and move to next character in the pattern and text.
- Case 3: The character is ‘+’ Here two cases arise : We match current character of text with the previous character of pattern. If there is no previous character that mean ‘+’ is the first character of pattern so we print result as “text do not match”. If the previous character is either ‘+’, ‘?’ or ‘*’ we replace it with the last character used by them.
- Case 4: The character is not a wildcard character If current character in text matches with current character in pattern, we move to next character in the pattern and text. If they do not match, wildcard pattern and text do not match.
The process for “*”, “?” is similar to wildcard pattern Matching for two characters:
Here we use a dp table that will contain two fields Struct DP { // value is true if match possible // for current indexes, else false. bool value; // Stores the character used // by the symbol that we used // later for symbol '+' char ch; }
Below c++ implementation of above idea.
CPP
// C++ program to implement wildcard // pattern matching algorithm #include <bits/stdc++.h> using namespace std; struct DP { bool value; char ch; }; // Function that matches input str with // given wildcard pattern bool strmatch(string str, string pattern, int n, int m) { // empty pattern can only match with // empty string if (m == 0) return (n == 0); // If first character of pattern is '+' if (pattern[0] == '+' ) return false ; // lookup table for storing results of // subproblems struct DP lookup[m + 1][n + 1]; // initialize lookup table to false for ( int i = 0; i <= m; i++) for ( int j = 0; j <= n; j++) { lookup[i][j].value = false ; lookup[i][j].ch = ' ' ; } // empty pattern can match with // empty string lookup[0][0].value = true ; // Only '*' can match with empty string for ( int j = 1; j <= n; j++) if (pattern[j - 1] == '*' ) lookup[j][0].value = lookup[j - 1][0].value; // fill the table in bottom-up fashion for ( int i = 1; i <= m; i++) { for ( int j = 1; j <= n; j++) { // Two cases if we see a '*' // a) We ignore ‘*’ character and move // to next character in the pattern, // i.e., ‘*’ indicates an empty sequence. // b) '*' character matches with ith // character in input if (pattern[i - 1] == '*' ) { lookup[i][j].value = lookup[i][j - 1].value || lookup[i - 1][j].value; lookup[i][j].ch = str[j - 1]; } // Current characters are considered as // matching in two cases // (a) current character of pattern is '?' else if (pattern[i - 1] == '?' ) { lookup[i][j].value = lookup[i - 1][j - 1].value; lookup[i][j].ch = str[j - 1]; } // (b) characters actually match else if (str[j - 1] == pattern[i - 1]) lookup[i][j].value = lookup[i - 1][j - 1].value; // Current character match else if (pattern[i - 1] == '+' ) // case 1: if previous character is // not symbol if (pattern[i - 2] != '+' || pattern[i - 2] != '*' || pattern[i - 2] != '?' ) if (pattern[i - 2] == str[j - 1]) { lookup[i][j].value = lookup[i - 1][j - 1].value; lookup[i][j].ch = str[j - 1]; } // case 2 : if previous character // is symbol (+, *, ? ) then we // compare current text character // with the character that is used by // the symbol at that point. we // access it by lookup[i-1][j-1] else if (str[j-1] == lookup[i-1][j-1].ch) { lookup[i][j].value = lookup[i - 1][j - 1].value; lookup[i][j].ch = lookup[i - 1][j - 1].ch; } // If characters don't match else lookup[i][j].value = false ; } } return lookup[m][n].value; } // Driver code int main() { string str = "baaabaaa" ; string pattern = "*****+ba***+" ; if (strmatch(str, pattern, str.length(), pattern.length())) cout << "Yes" << endl; else cout << "No" << endl; return 0; } |
Java
// Java code for the above approach import java.util.Arrays; class WildcardMatching { static class DP { boolean value; char ch; } // Function that matches input str with // given wildcard pattern static boolean strmatch(String str, String pattern) { int n = str.length(); int m = pattern.length(); // empty pattern can only match with // empty string if (m == 0 ) return (n == 0 ); // If first character of pattern is '+' if (pattern.charAt( 0 ) == '+' ) return false ; // lookup table for storing results of // subproblems DP[][] lookup = new DP[m + 1 ][n + 1 ]; // initialize lookup table to false for ( int i = 0 ; i <= m; i++) for ( int j = 0 ; j <= n; j++) { lookup[i][j] = new DP(); lookup[i][j].value = false ; lookup[i][j].ch = ' ' ; } // empty pattern can match with // empty string lookup[ 0 ][ 0 ].value = true ; // Only '*' can match with empty string for ( int j = 1 ; j <= n; j++) if (pattern.charAt(j - 1 ) == '*' ) lookup[j][ 0 ].value = lookup[j - 1 ][ 0 ].value; // fill the table in bottom-up fashion for ( int i = 1 ; i <= m; i++) { for ( int j = 1 ; j <= n; j++) { // Two cases if we see a '*' // a) We ignore ‘*’ character and move // to next character in the pattern, // i.e., ‘*’ indicates an empty sequence. // b) '*' character matches with ith // character in input if (pattern.charAt(i - 1 ) == '*' ) { lookup[i][j].value = lookup[i][j - 1 ].value || lookup[i - 1 ][j].value; lookup[i][j].ch = str.charAt(j - 1 ); } // Current characters are considered as // matching in two cases // (a) current character of pattern is '?' else if (pattern.charAt(i - 1 ) == '?' ) { lookup[i][j].value = lookup[i - 1 ][j - 1 ].value; lookup[i][j].ch = str.charAt(j - 1 ); } // (b) characters actually match else if (str.charAt(j - 1 ) == pattern.charAt(i - 1 )) lookup[i][j].value = lookup[i - 1 ][j - 1 ].value; // Current character match else if (pattern.charAt(i - 1 ) == '+' ) // case 1: if previous character is // not symbol if (pattern.charAt(i - 2 ) != '+' || pattern.charAt(i - 2 ) != '*' || pattern.charAt(i - 2 ) != '?' ) if (pattern.charAt(i - 2 ) == str.charAt(j - 1 )) { lookup[i][j].value = lookup[i - 1 ][j - 1 ] .value; lookup[i][j].ch = str.charAt(j - 1 ); } // case 2 : if previous character // is symbol (+, *, ? ) then we // compare current text character // with the character that is used // by the symbol at that point. we // access it by lookup[i-1][j-1] else if (str.charAt(j - 1 ) == lookup[i - 1 ][j - 1 ] .ch) { lookup[i][j].value = lookup[i - 1 ][j - 1 ] .value; lookup[i][j].ch = lookup[i - 1 ][j - 1 ].ch; } // If characters don't match else lookup[i][j].value = false ; } } return lookup[m][n].value; } public static void main(String[] args) { String str = "baaabaaa" ; String pattern = "*****+ba***+" ; if (strmatch(str, pattern)) System.out.println( "Yes" ); else System.out.println( "No" ); } } // This code is contributed by lokeshpotta20. |
Python3
# Python program to implement wildcard # pattern matching algorithm class DP: def __init__( self , value, ch): self .value = value; self .ch = ch; # Function that matches input str with # given wildcard pattern def strmatch( str , pattern, n, m): # empty pattern can only match with # empty string if (m = = 0 ): return (n = = 0 ); # If first character of pattern is '+' if (pattern[ 0 ] = = '+' ): return False ; # lookup table for storing results of # subproblems lookup = [[ 0 ] * (n + 1 ) for _ in range (m + 1 )]; # initialize lookup table to false for i in range ( 0 ,m + 1 ): for j in range ( 0 ,n + 1 ): lookup[i][j] = DP( False , ' ' ); # empty pattern can match with # empty string lookup[ 0 ][ 0 ].value = True ; # Only '*' can match with empty string for j in range ( 1 ,n + 1 ): if (pattern[j - 1 ] = = '*' ): lookup[j][ 0 ].value = lookup[j - 1 ][ 0 ].value; # fill the table in bottom-up fashion for i in range ( 1 ,m + 1 ): for j in range ( 1 ,n + 1 ): # Two cases if we see a '*' # a) We ignore ‘*’ character and move # to next character in the pattern, # i.e., ‘*’ indicates an empty sequence. # b) '*' character matches with ith # character in input if (pattern[i - 1 ] = = '*' ): lookup[i][j].value = lookup[i][j - 1 ].value or lookup[i - 1 ][j].value; lookup[i][j].ch = str [j - 1 ]; # Current characters are considered as # matching in two cases # (a) current character of pattern is '?' elif (pattern[i - 1 ] = = '?' ): lookup[i][j].value = lookup[i - 1 ][j - 1 ].value; lookup[i][j].ch = str [j - 1 ]; # (b) characters actually match elif ( str [j - 1 ] = = pattern[i - 1 ]): lookup[i][j].value = lookup[i - 1 ][j - 1 ].value; # Current character match elif (pattern[i - 1 ] = = '+' ): # case 1: if previous character is # not symbol if (pattern[i - 2 ] ! = '+' or pattern[i - 2 ] ! = '*' or pattern[i - 2 ] ! = '?' ): if (pattern[i - 2 ] = = str [j - 1 ]) : lookup[i][j].value = lookup[i - 1 ][j - 1 ].value; lookup[i][j].ch = str [j - 1 ]; # case 2 : if previous character # is symbol (+, *, ? ) then we # compare current text character # with the character that is used by # the symbol at that point. we # access it by lookup[i-1][j-1] elif ( str [j - 1 ] = = lookup[i - 1 ][j - 1 ].ch) : lookup[i][j].value = lookup[i - 1 ][j - 1 ].value; lookup[i][j].ch = lookup[i - 1 ][j - 1 ].ch; # If characters don't match else : lookup[i][j].value = False ; return lookup[m][n].value; # Driver code str = "baaabaaa" ; pattern = "*****+ba***+" ; if (strmatch( str , pattern, len ( str ), len (pattern))): print ( "Yes" ); else : print ( "No" ); |
C#
// C# program to implement wildcard // pattern matching algorithm using System; using System.Collections.Generic; class Gfg { class DP { public bool value; public char ch; public DP( bool value, char ch) { this .value=value; this .ch=ch; } } // Function that matches input str with // given wildcard pattern static bool strmatch( string str, string pattern, int n, int m) { // empty pattern can only match with // empty string if (m == 0) return (n == 0); // If first character of pattern is '+' if (pattern[0] == '+' ) return false ; // lookup table for storing results of // subproblems DP[,] lookup= new DP[m+1, n+1]; // initialize lookup table to false for ( int i = 0; i <= m; i++) { for ( int j = 0; j <= n; j++) { lookup[i,j]= new DP( false , ' ' ); } } // empty pattern can match with // empty string lookup[0,0].value = true ; // Only '*' can match with empty string for ( int j = 1; j <= n; j++) if (pattern[j - 1] == '*' ) lookup[j,0].value = lookup[j - 1,0].value; // fill the table in bottom-up fashion for ( int i = 1; i <= m; i++) { for ( int j = 1; j <= n; j++) { // Two cases if we see a '*' // a) We ignore ‘*’ character and move // to next character in the pattern, // i.e., ‘*’ indicates an empty sequence. // b) '*' character matches with ith // character in input if (pattern[i - 1] == '*' ) { lookup[i,j].value = lookup[i,j - 1].value || lookup[i - 1,j].value; lookup[i,j].ch = str[j - 1]; } // Current characters are considered as // matching in two cases // (a) current character of pattern is '?' else if (pattern[i - 1] == '?' ) { lookup[i,j].value = lookup[i - 1,j - 1].value; lookup[i,j].ch = str[j - 1]; } // (b) characters actually match else if (str[j - 1] == pattern[i - 1]) lookup[i,j].value = lookup[i - 1,j - 1].value; // Current character match else if (pattern[i - 1] == '+' ) // case 1: if previous character is // not symbol if (pattern[i - 2] != '+' || pattern[i - 2] != '*' || pattern[i - 2] != '?' ) if (pattern[i - 2] == str[j - 1]) { lookup[i,j].value = lookup[i - 1,j - 1].value; lookup[i,j].ch = str[j - 1]; } // case 2 : if previous character // is symbol (+, *, ? ) then we // compare current text character // with the character that is used by // the symbol at that point. we // access it by lookup[i-1,j-1] else if (str[j-1] == lookup[i-1,j-1].ch) { lookup[i,j].value = lookup[i - 1,j - 1].value; lookup[i,j].ch = lookup[i - 1,j - 1].ch; } // If characters don't match else lookup[i,j].value = false ; } } return lookup[m,n].value; } // Driver code public static void Main( string [] args) { string str = "baaabaaa" ; string pattern = "*****+ba***+" ; if (strmatch(str, pattern, str.Length, pattern.Length)) Console.Write( "Yes" ); else Console.Write( "No" ); } } // This code is contributed by ratiagrawal. |
Javascript
// Javascript program to implement wildcard // pattern matching algorithm class DP { constructor(value, ch) { this .value=value; this .ch=ch; } } // Function that matches input str with // given wildcard pattern function strmatch(str, pattern, n, m) { // empty pattern can only match with // empty string if (m == 0) return (n == 0); // If first character of pattern is '+' if (pattern[0] == '+' ) return false ; // lookup table for storing results of // subproblems let lookup = new DP(m+1); // initialize lookup table to false for (let i = 0; i <= m; i++){ lookup[i]= new DP(n+1); for (let j = 0; j <= n; j++) { lookup[i][j]= new DP( false , ' ' ); } } // empty pattern can match with // empty string lookup[0][0].value = true ; // Only '*' can match with empty string for (let j = 1; j <= n; j++) if (pattern[j - 1] == '*' ) lookup[j][0].value = lookup[j - 1][0].value; // fill the table in bottom-up fashion for (let i = 1; i <= m; i++) { for (let j = 1; j <= n; j++) { // Two cases if we see a '*' // a) We ignore ‘*’ character and move // to next character in the pattern, // i.e., ‘*’ indicates an empty sequence. // b) '*' character matches with ith // character in input if (pattern[i - 1] == '*' ) { lookup[i][j].value = lookup[i][j - 1].value || lookup[i - 1][j].value; lookup[i][j].ch = str[j - 1]; } // Current characters are considered as // matching in two cases // (a) current character of pattern is '?' else if (pattern[i - 1] == '?' ) { lookup[i][j].value = lookup[i - 1][j - 1].value; lookup[i][j].ch = str[j - 1]; } // (b) characters actually match else if (str[j - 1] == pattern[i - 1]) lookup[i][j].value = lookup[i - 1][j - 1].value; // Current character match else if (pattern[i - 1] == '+' ) // case 1: if previous character is // not symbol if (pattern[i - 2] != '+' || pattern[i - 2] != '*' || pattern[i - 2] != '?' ) if (pattern[i - 2] == str[j - 1]) { lookup[i][j].value = lookup[i - 1][j - 1].value; lookup[i][j].ch = str[j - 1]; } // case 2 : if previous character // is symbol (+, *, ? ) then we // compare current text character // with the character that is used by // the symbol at that point. we // access it by lookup[i-1][j-1] else if (str[j-1] == lookup[i-1][j-1].ch) { lookup[i][j].value = lookup[i - 1][j - 1].value; lookup[i][j].ch = lookup[i - 1][j - 1].ch; } // If characters don't match else lookup[i][j].value = false ; } } return lookup[m][n].value; } // Driver code let str = "baaabaaa" ; let pattern = "*****+ba***+" ; if (strmatch(str, pattern, str.length, pattern.length)) console.log( "Yes" ); else console.log( "No" ); // This code is contributed by poojaagarwal2. |
Yes
Time Complexity : O(n*m)
Auxiliary Space: O(n*m)
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 neveropen!