Given a dictionary of strings d[] and a string pat, find all strings in d[] that follow the same character pattern as pat. A string matches pat if there exists a one-to-one mapping between the characters of pat and the characters of the string. Return all matching strings.
Examples:
Input: d[] = ["abb", "abc", "xyz", "xyy"], pat = "foo"
Output: ["abb", "xyy"]
Explanation: "abb" and "xyy" match the pattern because the second and third characters are the same, just like in "foo".
Input: d[] = ["aab", "mno", "xyx", "aba", "ccc"], pat = "xyx"
Output: ["xyx", "aba"]
Explanation: "xyx" and "aba" match the pattern because the first and third characters are the same, while the second character is different. The mapping is consistent and one-to-one.
Table of Content
[Naive Approach] Check Every String Character by Character - O(n * k ^ 2) Time and O(1) Space
The idea is to check every pair of positions in the pattern and the word. If the equality relationship between characters is the same in both strings, the word matches the pattern.
#include <bits/stdc++.h>
using namespace std;
// Checks whether a single word matches the pattern
bool matchesPat(string &word, string &pat)
{
if (word.size() != pat.size())
return false;
int n = word.size();
// Compare every pair of positions
for (int i = 0; i < n; i++)
{
for (int j = i + 1; j < n; j++)
{
// Same pattern characters must correspond
// to same word characters
if (pat[i] == pat[j] && word[i] != word[j])
return false;
// Different pattern characters must correspond
// to different word characters
if (pat[i] != pat[j] && word[i] == word[j])
return false;
}
}
return true;
}
// Returns all dictionary words that match the pattern
vector<string> matchingStrings(vector<string> &d, string &pat)
{
vector<string> res;
for (string &word : d)
{
if (matchesPat(word, pat))
res.push_back(word);
}
return res;
}
// Driver code
int main()
{
vector<string> d = {"aab", "mno", "xyx", "aba", "ccc"};
string pat = "xyx";
vector<string> res = matchingStrings(d, pat);
cout << "[";
for (int i = 0; i < res.size(); i++)
{
cout << "\"" << res[i] << "\"";
if (i + 1 < res.size())
cout << ", ";
}
cout << "]";
return 0;
}
import java.util.ArrayList;
import java.util.Arrays;
// Checks whether a single word matches the pattern
class GFG {
static boolean matchesPat(String word, String pat)
{
if (word.length() != pat.length())
return false;
int n = word.length();
// Compare every pair of positions
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
// Same pattern characters must correspond
// to same word characters
if (pat.charAt(i) == pat.charAt(j)
&& word.charAt(i) != word.charAt(j))
return false;
// Different pattern characters must
// correspond to different word characters
if (pat.charAt(i) != pat.charAt(j)
&& word.charAt(i) == word.charAt(j))
return false;
}
}
return true;
}
// Returns all dictionary words that match the pattern
static ArrayList<String>
matchingStrings(ArrayList<String> d, String pat)
{
ArrayList<String> res = new ArrayList<>();
for (String word : d) {
if (matchesPat(word, pat))
res.add(word);
}
return res;
}
// Driver code
public static void main(String[] args)
{
ArrayList<String> d = new ArrayList<>(Arrays.asList(
"aab", "mno", "xyx", "aba", "ccc"));
String pat = "xyx";
ArrayList<String> res = matchingStrings(d, pat);
System.out.print("[");
for (int i = 0; i < res.size(); i++) {
System.out.print("\"" + res.get(i) + "\"");
if (i + 1 < res.size())
System.out.print(", ");
}
System.out.print("]");
}
}
# Checks whether a single word matches the pattern
def matchesPat(word, pat):
if len(word) != len(pat):
return False
n = len(word)
# Compare every pair of positions
for i in range(n):
for j in range(i + 1, n):
# Same pattern characters must correspond
# to same word characters
if pat[i] == pat[j] and word[i] != word[j]:
return False
# Different pattern characters must correspond
# to different word characters
if pat[i] != pat[j] and word[i] == word[j]:
return False
return True
# Returns all dictionary words that match the pattern
def matchingStrings(d, pat):
res = []
for word in d:
if matchesPat(word, pat):
res.append(word)
return res
# Driver code
if __name__ == "__main__":
d = ["aab", "mno", "xyx", "aba", "ccc"]
pat = "xyx"
res = matchingStrings(d, pat)
print('[', end='')
for i in range(len(res)):
print(f'"{res[i]}"', end='')
if i + 1 < len(res):
print(', ', end='')
print(']')
using System;
using System.Collections.Generic;
public class GFG {
// Checks whether a single word matches the pattern
public bool MatchesPat(string word, string pat)
{
if (word.Length != pat.Length)
return false;
int n = word.Length;
// Compare every pair of positions
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
// Same pattern characters must correspond
// to same word characters
if (pat[i] == pat[j] && word[i] != word[j])
return false;
// Different pattern characters must
// correspond to different word characters
if (pat[i] != pat[j] && word[i] == word[j])
return false;
}
}
return true;
}
// Returns all dictionary words that match the pattern
public List<string> MatchingStrings(List<string> d,
string pat)
{
List<string> res = new List<string>();
foreach(string word in d)
{
if (MatchesPat(word, pat))
res.Add(word);
}
return res;
}
// Driver code
public static void Main()
{
List<string> d
= new List<string>{ "aab", "mno", "xyx", "aba",
"ccc" };
string pat = "xyx";
GFG obj = new GFG();
List<string> res = obj.MatchingStrings(d, pat);
Console.Write("[");
for (int i = 0; i < res.Count; i++) {
Console.Write("\"" + res[i] + "\"");
if (i + 1 < res.Count)
Console.Write(", ");
}
Console.Write("]");
}
}
// Checks whether a single word matches the pattern
function matchesPat(word, pat)
{
if (word.length !== pat.length)
return false;
let n = word.length;
// Compare every pair of positions
for (let i = 0; i < n; i++) {
for (let j = i + 1; j < n; j++) {
// Same pattern characters must correspond
// to same word characters
if (pat[i] === pat[j] && word[i] !== word[j])
return false;
// Different pattern characters must correspond
// to different word characters
if (pat[i] !== pat[j] && word[i] === word[j])
return false;
}
}
return true;
}
// Returns all dictionary words that match the pattern
function matchingStrings(d, pat)
{
let res = [];
for (let word of d) {
if (matchesPat(word, pat))
res.push(word);
}
return res;
}
// Driver code
function main()
{
let d = [ "aab", "mno", "xyx", "aba", "ccc" ];
let pat = "xyx";
let res = matchingStrings(d, pat);
process.stdout.write("[");
for (let i = 0; i < res.length; i++) {
process.stdout.write(`"${res[i]}"`);
if (i + 1 < res.length)
process.stdout.write(", ");
}
process.stdout.write("]");
}
main();
Output
["xyx", "aba"]
Time Complexity: O(n * k ^ 2)
Auxiliary Space: O(1)
[Expected Approach] Using Index Mapping - O(n * k) Time and O(1) Space
The idea is to store the last occurrence index of each character in both the pattern and the word. While traversing the strings, the previous occurrence positions of the current pattern character and word character must be the same. If they differ, the word does not follow the pattern; otherwise, it matches.
Let us understand with example:
Input: d[] = ["aab", "mno", "xyx", "aba", "ccc"], pat = "xyx"
- Initialize lastPat[] and lastWord[] with -1 to store the last occurrence of each character.
- For each word, compare corresponding characters of the pattern and word. Their previous occurrence positions must match.
- For "xyx": mappings remain consistent (x -> x, y -> y, x -> x), so it is added to the result.
- For "aba": mappings remain consistent (x -> a, y -> b, x -> a), so it is added to the result.
- Words "aab", "mno", and "ccc" violate the pattern mapping, so they are rejected. Final answer: ["xyx", "aba"].
#include <bits/stdc++.h>
using namespace std;
// Checks whether a single word follows the same
// character pattern as pat.
bool matchesPat(string &word, string &pat)
{
// Words of different lengths cannot match.
if (word.size() != pat.size())
return false;
// lastPat[c] stores the most recent position
// where character c appeared in pat.
int lastPat[128];
// lastWord[c] stores the most recent position
// where character c appeared in word.
int lastWord[128];
fill(lastPat, lastPat + 128, -1);
fill(lastWord, lastWord + 128, -1);
for (int i = 0; i < (int)word.size(); i++)
{
char p = pat[i];
char w = word[i];
// For matching patterns, both characters
// must have been seen previously at the
// same position.
if (lastPat[p] != lastWord[w])
return false;
// Record the current position.
lastPat[p] = i;
lastWord[w] = i;
}
return true;
}
// Returns all dictionary words that match pat.
vector<string> matchingStrings(vector<string> &d, string &pat)
{
vector<string> res;
// Check each word independently.
for (string &word : d)
{
if (matchesPat(word, pat))
{
res.push_back(word);
}
}
return res;
}
// Driver code
int main()
{
vector<string> d = {"aab", "mno", "xyx", "aba", "ccc"};
string pat = "xyx";
vector<string> res = matchingStrings(d, pat);
cout << "[";
for (int i = 0; i < res.size(); i++)
{
cout << "\"" << res[i] << "\"";
if (i + 1 < res.size())
cout << ", ";
}
cout << "]";
return 0;
}
import java.util.ArrayList;
import java.util.Arrays;
// Checks whether a single word follows the same
// character pattern as pat.
public class GFG {
public static boolean matchesPat(String word,
String pat)
{
// Words of different lengths cannot match.
if (word.length() != pat.length())
return false;
// lastPat[c] stores the most recent position
// where character c appeared in pat.
int[] lastPat = new int[128];
// lastWord[c] stores the most recent position
// where character c appeared in word.
int[] lastWord = new int[128];
Arrays.fill(lastPat, -1);
Arrays.fill(lastWord, -1);
for (int i = 0; i < word.length(); i++) {
char p = pat.charAt(i);
char w = word.charAt(i);
// For matching patterns, both characters
// must have been seen previously at the
// same position.
if (lastPat[p] != lastWord[w])
return false;
// Record the current position.
lastPat[p] = i;
lastWord[w] = i;
}
return true;
}
// Returns all dictionary words that match pat.
public static ArrayList<String>
matchingStrings(ArrayList<String> d, String pat)
{
ArrayList<String> res = new ArrayList<>();
// Check each word independently.
for (String word : d) {
if (matchesPat(word, pat)) {
res.add(word);
}
}
return res;
}
// Driver code
public static void main(String[] args)
{
ArrayList<String> d = new ArrayList<>(Arrays.asList(
"aab", "mno", "xyx", "aba", "ccc"));
String pat = "xyx";
ArrayList<String> res = matchingStrings(d, pat);
System.out.print("[");
for (int i = 0; i < res.size(); i++) {
System.out.print("\"" + res.get(i) + "\"");
if (i + 1 < res.size())
System.out.print(", ");
}
System.out.print("]");
}
}
# Checks whether a single word follows the same
# character pattern as pat.
def matchesPat(word, pat):
# Words of different lengths cannot match.
if len(word) != len(pat):
return False
# lastPat[c] stores the most recent position
# where character c appeared in pat.
lastPat = [-1] * 128
# lastWord[c] stores the most recent position
# where character c appeared in word.
lastWord = [-1] * 128
for i in range(len(word)):
p = ord(pat[i])
w = ord(word[i])
# For matching patterns, both characters
# must have been seen previously at the
# same position.
if lastPat[p] != lastWord[w]:
return False
# Record the current position.
lastPat[p] = i
lastWord[w] = i
return True
# Returns all dictionary words that match pat.
def matchingStrings(d, pat):
res = []
# Check each word independently.
for word in d:
if matchesPat(word, pat):
res.append(word)
return res
# Driver code
if __name__ == "__main__":
d = ["aab", "mno", "xyx", "aba", "ccc"]
pat = "xyx"
res = matchingStrings(d, pat)
print('[', end='')
for i in range(len(res)):
print(f'"{res[i]}"', end='')
if i + 1 < len(res):
print(', ', end='')
print(']')
using System;
using System.Collections.Generic;
public class GFG {
// Checks whether a single word follows the same
// character pattern as pat.
public bool MatchesPat(string word, string pat)
{
// Words of different lengths cannot match.
if (word.Length != pat.Length)
return false;
// lastPat[c] stores the most recent position
// where character c appeared in pat.
int[] lastPat = new int[128];
// lastWord[c] stores the most recent position
// where character c appeared in word.
int[] lastWord = new int[128];
Array.Fill(lastPat, -1);
Array.Fill(lastWord, -1);
for (int i = 0; i < word.Length; i++) {
char p = word[i];
char w = pat[i];
// For matching patterns, both characters
// must have been seen previously at the
// same position.
if (lastPat[p] != lastWord[w])
return false;
// Record the current position.
lastPat[p] = i;
lastWord[w] = i;
}
return true;
}
// Returns all dictionary words that match pat.
public List<string> MatchingStrings(List<string> d,
string pat)
{
List<string> res = new List<string>();
// Check each word independently.
foreach(string word in d)
{
if (MatchesPat(word, pat)) {
res.Add(word);
}
}
return res;
}
// Driver code
public static void Main()
{
List<string> d
= new List<string>{ "aab", "mno", "xyx", "aba",
"ccc" };
string pat = "xyx";
GFG obj = new GFG();
List<string> res = obj.MatchingStrings(d, pat);
Console.Write("[");
for (int i = 0; i < res.Count; i++) {
Console.Write("\"" + res[i] + "\"");
if (i + 1 < res.Count)
Console.Write(", ");
}
Console.Write("]");
}
}
// Checks whether a single word follows the same
// character pattern as pat.
function matchesPat(word, pat)
{
// Words of different lengths cannot match.
if (word.length !== pat.length)
return false;
// lastPat[c] stores the most recent position
// where character c appeared in pat.
let lastPat = new Array(128).fill(-1);
// lastWord[c] stores the most recent position
// where character c appeared in word.
let lastWord = new Array(128).fill(-1);
for (let i = 0; i < word.length; i++) {
let p = pat.charCodeAt(i);
let w = word.charCodeAt(i);
// For matching patterns, both characters
// must have been seen previously at the
// same position.
if (lastPat[p] !== lastWord[w])
return false;
// Record the current position.
lastPat[p] = i;
lastWord[w] = i;
}
return true;
}
// Returns all dictionary words that match pat.
function matchingStrings(d, pat)
{
let res = [];
// Check each word independently.
for (let word of d) {
if (matchesPat(word, pat)) {
res.push(word);
}
}
return res;
}
// Driver code
let d = [ "aab", "mno", "xyx", "aba", "ccc" ];
let pat = "xyx";
let res = matchingStrings(d, pat);
console.log("["
+ res.map(word => "\"" + word + "\"").join(", ")
+ "]");
Output
["xyx", "aba"]
Time Complexity: O(n * k)
Auxiliary Space: O(1)