Given a string, find out if string follows a given pattern or not without using any regular expressions.
Examples:
Input: string - GraphTreesGraph pattern - aba Output: a->Graph b->Trees Input: string - GraphGraphGraph pattern - aaa Output: a->Graph Input: string - GeeksforGeeks pattern - GfG Output: G->Geeks f->for Input: string - GeeksforGeeks pattern - GG Output: No solution exists
We can solve this problem with the help of Backtracking. For each character in the pattern, if the character is not seen before, we consider all possible sub-strings and recurse to see if it leads to the solution or not. We maintain a map that stores sub-string mapped to a pattern character. If pattern character is seen before, we use the same sub-string present in the map. If we found a solution, for each distinct character in the pattern, we print string mapped to it using our map.
Below is C++ implementation of above idea –
// C++ program to find out if string follows // a given pattern or not #include <bits/stdc++.h> using namespace std;
/* Function to find out if string follows a given pattern or not
str - given string
n - length of given string
i - current index in input string
pat - given pattern
m - length of given pattern
j - current index in given pattern
map - stores mapping between pattern and string */
bool patternMatchUtil(string str, int n, int i,
string pat, int m, int j,
unordered_map< char , string>& map)
{ // If both string and pattern reach their end
if (i == n && j == m)
return true ;
// If either string or pattern reach their end
if (i == n || j == m)
return false ;
// read next character from the pattern
char ch = pat[j];
// if character is seen before
if (map.find(ch)!= map.end())
{
string s = map[ch];
int len = s.size();
// consider next len characters of str
string subStr = str.substr(i, len);
// if next len characters of string str
// don't match with s, return false
if (subStr.compare(s))
return false ;
// if it matches, recurse for remaining characters
return patternMatchUtil(str, n, i + len, pat, m,
j + 1, map);
}
// If character is seen for first time, try out all
// remaining characters in the string
for ( int len = 1; len <= n - i; len++)
{
// consider substring that starts at position i
// and spans len characters and add it to map
map[ch] = str.substr(i, len);
// see if it leads to the solution
if (patternMatchUtil(str, n, i + len, pat, m,
j + 1, map))
return true ;
// if not, remove ch from the map
map.erase(ch);
}
return false ;
} // A wrapper over patternMatchUtil()function bool patternMatch(string str, string pat, int n, int m)
{ if (n < m)
return false ;
// create an empty hashmap
unordered_map< char , string> map;
// store result in a boolean variable res
bool res = patternMatchUtil(str, n, 0, pat, m, 0, map);
// if solution exists, print the mappings
for ( auto it = map.begin(); res && it != map.end(); it++)
cout << it->first << "->" << it->second << endl;
// return result
return res;
} // Driver code int main()
{ string str = "GeeksforGeeks" , pat = "GfG" ;
int n = str.size(), m = pat.size();
if (!patternMatch(str, pat, n, m))
cout << "No Solution exists" ;
return 0;
} |
import java.util.HashMap;
import java.util.Map;
class Main
{ // Function to determine if given pattern matches with a string or not
public static boolean match(String str, int i,
String pat, int j,
Map<Character, String> map)
{
int n = str.length(), m = pat.length();
// base condition
if (n < m) {
return false ;
}
// if both pattern and the string reaches end
if (i == n && j == m) {
return true ;
}
// if either string or pattern reaches end
if (i == n || j == m) {
return false ;
}
// consider next character from the pattern
char curr = pat.charAt(j);
// if the character is seen before
if (map.containsKey(curr))
{
String s = map.get(curr);
int k = s.length();
// ss stores next k characters of the given string
String ss;
if (i + k < str.length()) {
ss = str.substring(i, i + k);
} else {
ss = str.substring(i);
}
// return false if next k characters doesn't match with s
if (ss.compareTo(s) != 0 ) {
return false ;
}
// recur for remaining characters if next k characters matches
return match(str, i + k, pat, j + 1 , map);
}
// process all remaining characters in the string if current
// character is never seen before
for ( int k = 1 ; k <= n - i; k++)
{
// insert substring formed by next k characters of the string
// into the map
map.put(curr, str.substring(i, i + k));
// check if it leads to the solution
if (match(str, i + k, pat, j + 1 , map)) {
return true ;
}
// else backtrack - remove current character from the map
map.remove(curr);
}
return false ;
}
public static void main(String[] args)
{
// input string and pattern
String str = "GeeksforGeeks" ;
String pat = "GfG" ;
// create a map to store mappings between the pattern and string
Map<Character, String> map = new HashMap<>();
// check for solution
if (match(str, 0 , pat, 0 , map))
{
for (Map.Entry<Character, String> entry: map.entrySet()) {
System.out.println(entry.getKey() + "->" + entry.getValue());
}
}
else {
System.out.println( "Solution doesn't exist" );
}
}
} //This code is contributed by Priyadarshini Kumari |
# Function to determine if given pattern matches with a string or not def match( str , pat, dict , i = 0 , j = 0 ):
n = len ( str )
m = len (pat)
# base condition
if n < m:
return False
# if both pattern and the string reaches end
if i = = n and j = = m:
return True
# if either string or pattern reaches end
if i = = n or j = = m:
return False
# consider next character from the pattern
curr = pat[j]
# if the character is seen before
if curr in dict :
s = dict [curr]
k = len (s)
# ss stores next k characters of the given string
if i + k < len ( str ):
ss = str [i:i + k]
else :
ss = str [i:]
# return false if next k characters doesn't match with s
if ss ! = s:
return False
# recur for remaining characters if next k characters matches
return match( str , pat, dict , i + k, j + 1 )
# process all remaining characters in the string if current
# character is never seen before
for k in range ( 1 , n - i + 1 ):
# insert substring formed by next k characters of the string
# into the dictionary
dict [curr] = str [i:i + k]
# check if it leads to the solution
if match( str , pat, dict , i + k, j + 1 ):
return True
# else backtrack - remove current character from the dictionary
dict .pop(curr)
return False
if __name__ = = '__main__' :
# input string and pattern
str = "GeeksforGeeks"
pat = "GfG"
# create a dictionary to store mappings between the pattern and string
dict = {}
# check for solution
if match( str , pat, dict ):
print ( dict )
else :
print ( "Solution doesn't exist" )
# This code is contributed by Priyadarshini Kumari |
// C# program to find out if string follows // a given pattern or not using System;
using System.Collections.Generic;
public class GFG {
/* Function to find out if string follows a given
pattern or not
str - given string
n - length of given string
i - current index in input string
pat - given pattern
m - length of given pattern
j - current index in given pattern
map - stores mapping between pattern and string */
static bool patternMatchUtil( string str, int n, int i,
string pat, int m, int j,
Dictionary< char , string > map)
{
// If both string and pattern reach their end
if (i == n && j == m)
return true ;
// If either string or pattern reach their end
if (i == n || j == m)
return false ;
// read next character from the pattern
char ch = pat[j];
// if character is seen before
if (map.ContainsKey(ch)) {
string s = map[ch];
int len = s.Length;
if (len <= n - i) {
// consider next len characters of str
string subStr = str.Substring(i, len);
// if next len characters of string str
// don't match with s, return false
if (subStr != s)
return false ;
// if it matches, recurse for remaining characters
return patternMatchUtil(str, n, i + len, pat, m, j + 1, map);
}
else {
return false ;
}
}
// If character is seen for first time, try out all
// remaining characters in the string
for ( int len = 1; len <= n - i; len++) {
// consider substring that starts at position i
// and spans len characters and add it to map
map[ch] = str.Substring(i, len);
// see if it leads to the solution
if (patternMatchUtil(str, n, i + len, pat, m, j + 1, map))
return true ;
// if not, remove ch from the map
map.Remove(ch);
}
return false ;
}
// A wrapper over patternMatchUtil()function
static bool patternMatch( string str, string pat, int n, int m) {
if (n < m)
return false ;
// create an empty hashmap (Dictionary)
Dictionary< char , string > map = new Dictionary< char , string >();
// store result in a boolean variable res
bool res = patternMatchUtil(str, n, 0, pat, m, 0, map);
// if solution exists, print the mappings
foreach ( var item in map) {
Console.WriteLine(item.Key + "->" + item.Value);
}
// return result
return res;
}
// Driver Code
static public void Main( string [] args) {
string str = "GeeksforGeeks" ;
string pat = "GfG" ;
int n = str.Length;
int m = pat.Length;
if (!patternMatch(str, pat, n, m))
Console.WriteLine( "No Solution exists" );
}
} // This Code is Contributed by Prasad Kandekar(prasad264) |
<script> // Javascript program to find out if string follows // a given pattern or not /* Function to find out if string follows a given pattern or not
str - given string
n - length of given string
i - current index in input string
pat - given pattern
m - length of given pattern
j - current index in given pattern
map - stores mapping between pattern and string */
function patternMatchUtil(str, n, i, pat, m, j, map) {
// If both string and pattern reach their end
if (i == n && j == m)
return true ;
// If either string or pattern reach their end
if (i == n || j == m)
return false ;
// read next character from the pattern
let ch = pat[j];
// if character is seen before
if (map.has(ch)) {
let s = map.get(ch);
let len = s.length;
// consider next len characters of str
let subStr = str.substr(i, len);
// if next len characters of string str
// don't match with s, return false
if (subStr != s)
return false ;
// if it matches, recurse for remaining characters
return patternMatchUtil(str, n, i + len, pat, m,
j + 1, map);
}
// If character is seen for first time, try out all
// remaining characters in the string
for (let len = 1; len <= n - i; len++) {
// consider substring that starts at position i
// and spans len characters and add it to map
map.set(ch, str.substr(i, len));
// see if it leads to the solution
if (patternMatchUtil(str, n, i + len, pat, m, j + 1, map))
return true ;
// if not, remove ch from the map
map. delete (ch);
}
return false ;
} // A wrapper over patternMatchUtil()function function patternMatch(str, pat, n, m) {
if (n < m)
return false ;
// create an empty hashmap
let map = new Map();
// store result in a boolean variable res
let res = patternMatchUtil(str, n, 0, pat, m, 0, map);
// if solution exists, print the mappings
console.log(map)
for (it of [...map.keys()].reverse())
document.write(it + "->" + map.get(it) + "<br>" );
// return result
return res;
} // Driver code let str = "GeeksforGeeks" , pat = "GfG" ;
let n = str.length let m = pat.length; if (!patternMatch(str, pat, n, m))
document.write( "No Solution exists" );
// This code is contributed by saurabh_jaiswal.
</script> |
Output:
f->for G->Geeks
Time complexity of this code is O(2^m), where m is the length of the pattern. This is because in the worst case, the algorithm may have to try all possible combinations of substrings of the string to find a match with the pattern.
Space complexity is O(m), where m is the length of the pattern, as the mapping between the pattern and the string is stored in a hash map with m characters.