Open In App

Match a pattern and String without using regular expressions

Last Updated : 11 May, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

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:

  • Begin with indices i = 0 in the word and j = 0 in the pattern, and an empty map mp
  • If both i and j reach the ends of word and pat, return true; if only one does, return false.
  • Let ch = pat[j].
  • If ch is already in mp, let s = mp[ch], and check that the substring of word starting at i with length s.size() equals s; if not, return false, otherwise recurse with i += s.size() and j++.
  • If ch is not yet in mp, build candidate substrings cur by appending one more character at a time from word[i] onward; for each cur, set mp[ch] = cur and recurse with advanced indices; if the recursive call returns true, propagate success; if not, erase mp[ch] and try a longer cur.
  • In patternMatch, call this utility starting at (0,0); if it returns true, collect each (char, string) pair from mp into the result vector.

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.


Next Article
Article Tags :
Practice Tags :

Similar Reads