Match a pattern and String without using regular expressions (original) (raw)

Last Updated : 11 May, 2025

Given two strings, **word and **pat, your task is to check if the string **word follows the pattern of string **pat. If the string follows the pattern, find the substring associated with each character of the given pattern string, else print -1.

**Examples:

**Input: word = "GraphTreesGraph", pat = "aba"
**Output: a : Graph
b : Trees
**Explanation: The character 'a' and 'b' of the pattern string can be mapped with substring "Graph" and "Trees" of the string **word respectively.

**Input: word = "GraphGraphGraph", pat = "aaa"
**Output: a : Graph
**Explanation: The character 'a' of the pattern string can be mapped with substring "Graph" of the string **word.

**Input: word = "GeeksforGeeks", pat = "gg"
**Output: -1
**Explanation: Since the pattern consists only of ‘g’ characters, a valid mapping would split the **word into two identical halves—but those halves aren’t equal, so no solution exists.

Using Backtracking - O(n ^ m) Time and O(n + m) Space

The idea is to use backtracking to explore every way of assigning substrings of the input **word**to each character in the pattern pat, storing each assignment in the map mp. Whenever a pattern character reappears, we don’t try new substrings but instead verify that the next segment of word matches its existing mapping. If we manage to reach end of both the string, we’ve found a valid mapping.

Follow the below given steps:

Below is given the **implementation:

CPP `

#include <bits/stdc++.h> using namespace std;

// recursive function to check all // possible pattern - word mappings bool patternMatchUtil(int i, int j, string &word, string &pat, unordered_map<char, string> &mp) { int n = word.size(), m = pat.size();

// 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 (mp.count(ch) != 0) {

    // get the string mapped to the character
    string s = mp[ch];
    int len = s.size();

    // consider next len characters of str
    // check if they match with s
    for(int k = 0; k < len; k++) {
        if (i + k >= n || word[i + k] != s[k])
            return false;
    }

    // if it matches, 
    // recurse for remaining characters
    return patternMatchUtil(i + len, j + 1, word, pat, mp);
}

// if character is not seen before
// try all possible substrings of str
string cur = "";
for (int ind = i; ind < n; ind++) {

    // add current character to the substring
    cur += word[ind];

    // map the character to the substring
    mp[ch] = cur;

    // see if it leads to the solution
    if (patternMatchUtil(ind + 1, j + 1, word, pat, mp))
        return true;

    // if not, remove ch from the map
    mp.erase(ch);
}

return false;

}

vector<pair<char, string>> patternMatch(string &word, string &pat) {

// to store the resultant pairs
vector<pair<char, string>> res;

// to store the character-word mappings
unordered_map<char, string> mp;

// check if the solution exists
bool ans = patternMatchUtil(0, 0, word, pat, mp);

// if the solution exists, store the mappings
if(ans) {
    for (auto i:mp) {
        res.push_back({i.first, i.second});
    }
}
return res;

}

int main() { string str = "GraphTreesGraph"; string pat = "aba"; vector<pair<char, string>> ans = patternMatch(str, pat); if(ans.empty()) { cout << -1; } else { sort(ans.begin(), ans.end()); for(auto i: ans) { cout << i.first << " : " << i.second << endl; } } return 0; }

Java

import java.util.*;

class GfG {

// recursive function to check all
// possible pattern - word mappings
static boolean patternMatchUtil(int i, int j, String word, 
    String pat, Map<Character, String> mp) {
    int n = word.length(), m = pat.length();

    // 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.charAt(j);

    // if character is seen before
    if (mp.containsKey(ch)) {

        // get the string mapped to the character
        String s = mp.get(ch);
        int len = s.length();

        // consider next len characters of str
        // check if they match with s
        for(int k = 0; k < len; k++) {
            if (i + k >= n || word.charAt(i + k) != s.charAt(k))
                return false;
        }

        // if it matches, recurse for remaining characters
        return patternMatchUtil(i + len, j + 1, word, pat, mp);
    }

    // if character is not seen before
    // try all possible substrings of str
    String cur = "";
    for (int ind = i; ind < n; ind++) {

        // add current character to the substring
        cur += word.charAt(ind);

        // map the character to the substring
        mp.put(ch, cur);

        // see if it leads to the solution
        if (patternMatchUtil(ind + 1, j + 1, word, pat, mp))
            return true;

        // if not, remove ch from the map
        mp.remove(ch);
    }

    return false;
}

static List<AbstractMap.SimpleEntry<Character, String>>
patternMatch(String word, String pat) {

    // to store the resultant pairs
    List<AbstractMap.SimpleEntry<Character, String>> res = 
    new ArrayList<>();

    // to store the character-word mappings
    Map<Character, String> mp = new HashMap<>();

    // check if the solution exists
    boolean ans = patternMatchUtil(0, 0, word, pat, mp);

    // if the solution exists, store the mappings
    if(ans) {
        for (Map.Entry<Character, String> i : mp.entrySet()) {
            res.add(new AbstractMap.SimpleEntry<>
            (i.getKey(), i.getValue()));
        }
    }
    return res;
}

public static void main(String[] args) {
    String str = "GraphTreesGraph";
    String pat = "aba";
    List<AbstractMap.SimpleEntry<Character, String>> ans = 
    patternMatch(str, pat);
    if(ans.isEmpty()) {
        System.out.print(-1);
    } else {
        for(AbstractMap.SimpleEntry<Character, String> i: ans) {
            System.out.println(i.getKey() + " : " + i.getValue());
        }
    }
}

}

Python

recursive function to check all

possible pattern - word mappings

def patternMatchUtil(i, j, word, pat, mp): n, m = len(word), len(pat)

# If both string and pattern reach their end
if i == n and j == m:
    return True

# If either string or pattern reach their end
if i == n or j == m:
    return False

# read next character from the pattern
ch = pat[j]

# if character is seen before
if ch in mp:

    # get the string mapped to the character
    s = mp[ch]
    length = len(s)

    # consider next len characters of str
    # check if they match with s
    for k in range(length):
        if i + k >= n or word[i + k] != s[k]:
            return False

    # if it matches, recurse for remaining characters
    return patternMatchUtil(i + length, j + 1, word, pat, mp)

# if character is not seen before
# try all possible substrings of str
cur = ""
for ind in range(i, n):

    # add current character to the substring
    cur += word[ind]

    # map the character to the substring
    mp[ch] = cur

    # see if it leads to the solution
    if patternMatchUtil(ind + 1, j + 1, word, pat, mp):
        return True

    # if not, remove ch from the map
    del mp[ch]

return False

def patternMatch(word, pat):

# to store the resultant pairs
res = []

# to store the character-word mappings
mp = {}

# check if the solution exists
ans = patternMatchUtil(0, 0, word, pat, mp)

# if the solution exists, store the mappings
if ans:
    for i in mp.items():
        res.append((i[0], i[1]))
return res

if name == "main": str = "GraphTreesGraph" pat = "aba" ans = patternMatch(str, pat) if not ans: print(-1) else: for i in ans: print(i[0], " : ", i[1])

C#

using System; using System.Collections.Generic;

class GfG {

// recursive function to check all
// possible pattern - word mappings
static bool patternMatchUtil(int i, int j, string word, 
    string pat, Dictionary<char, string> mp) {
    int n = word.Length, m = pat.Length;

    // 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 (mp.ContainsKey(ch)) {

        // get the string mapped to the character
        string s = mp[ch];
        int len = s.Length;

        // consider next len characters of str
        // check if they match with s
        for(int k = 0; k < len; k++) {
            if (i + k >= n || word[i + k] != s[k])
                return false;
        }

        // if it matches, recurse for remaining characters
        return patternMatchUtil(i + len, j + 1, word, pat, mp);
    }

    // if character is not seen before
    // try all possible substrings of str
    string cur = "";
    for (int ind = i; ind < n; ind++) {

        // add current character to the substring
        cur += word[ind];

        // map the character to the substring
        mp[ch] = cur;

        // see if it leads to the solution
        if (patternMatchUtil(ind + 1, j + 1, word, pat, mp))
            return true;

        // if not, remove ch from the map
        mp.Remove(ch);
    }

    return false;
}

static List<KeyValuePair<char, string>>
    patternMatch(string word, string pat) {

    // to store the resultant pairs
    List<KeyValuePair<char, string>> res = 
    new List<KeyValuePair<char, string>>();

    // to store the character-word mappings
    Dictionary<char, string> mp = 
    new Dictionary<char, string>();

    // check if the solution exists
    bool ans = patternMatchUtil(0, 0, word, pat, mp);

    // if the solution exists, store the mappings
    if(ans) {
        foreach (var i in mp) {
            res.Add(new KeyValuePair<char, string>(i.Key, i.Value));
        }
    }
    return res;
}

static void Main() {
    string str = "GraphTreesGraph";
    string pat = "aba";
    var ans = patternMatch(str, pat);
    if(ans.Count == 0) {
        Console.Write(-1);
    } else {
        foreach(var i in ans) {
            Console.WriteLine(i.Key + " : " + i.Value);
        }
    }
}

}

JavaScript

// recursive function to check all // possible pattern - word mappings function patternMatchUtil(i, j, word, pat, mp) { const n = word.length, m = pat.length;

// 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
const ch = pat[j];

// if character is seen before
if (mp.hasOwnProperty(ch)) {

    // get the string mapped to the character
    const s = mp[ch];
    const len = s.length;

    // consider next len characters of str
    // check if they match with s
    for (let k = 0; k < len; k++) {
        if (i + k >= n || word[i + k] !== s[k])
            return false;
    }

    // if it matches, recurse for remaining characters
    return patternMatchUtil(i + len, j + 1, word, pat, mp);
}

// if character is not seen before
// try all possible substrings of str
let cur = "";
for (let ind = i; ind < n; ind++) {

    // add current character to the substring
    cur += word[ind];

    // map the character to the substring
    mp[ch] = cur;

    // see if it leads to the solution
    if (patternMatchUtil(ind + 1, j + 1, word, pat, mp))
        return true;

    // if not, remove ch from the map
    delete mp[ch];
}

return false;

}

function patternMatch(word, pat) {

// to store the resultant pairs
const res = [];

// to store the character-word mappings
const mp = {};

// check if the solution exists
const ans = patternMatchUtil(0, 0, word, pat, mp);

// if the solution exists, store the mappings
if(ans) {
    for (const ch in mp) {
        res.push([ch, mp[ch]]);
    }
}
return res;

}

const str = "GraphTreesGraph"; const pat = "aba"; const ans = patternMatch(str, pat); if(ans.length === 0) { console.log(-1); } else { ans.forEach(i => console.log(i[0] + " : " + i[1])); }

`

Output

a : Graph b : Trees

**Time Complexity: O(n ^ m),in the worst case, the recursive function will check for all possible combinations of string word and pat.
**Space Complexity: O(n + m), to store the character - word mappings.