Given a 2D integer matrix mat[][] and a 2D character matrix pat[][]. Where 0 <= mat[r][c] <= 9 and each element of pat is either a digit or a lowercase English letter. The task is to find a submatrix of mat that matches pat. An integer matrix part matches pat if we can replace cells containing letters in pat with some digits (each distinct letter with a unique digit) in such a way that the resulting matrix becomes identical to the integer matrix part. In other words,
The matrices have identical dimensions.
- If pat[r][c] is a digit, then part[r][c] must be the same digit.
- If pat[r][c] is a letter x:
- For every pat[i][j] == x, part[i][j] must be the same as part[r][c].
- For every pat[i][j] != x, part[i][j] must be different than part[r][c].
Return an array of length 2 containing the row number and column number of the upper-left corner of a submatrix of mat which matches pat. If there is more than one such submatrix, return the coordinates of the submatrix with the lowest row index, and in case there is still a tie, return the coordinates of the submatrix with the lowest column index. If there are no suitable answers, return {-1, -1}.
Example:
Input: mat = {{1,2,2},{2,2,3},{2,3,3}}, pat = {"ab","bb"}
Output: {0,0}
Explanation: If we consider this mapping: "a" -> 1 and "b" -> 2; the submatrix with the upper-left corner (0,0) is a match as outlined in the matrix above.
Note that the submatrix with the upper-left corner (1,1) is also a match but since it comes after the other one, we return {0,0}.Input: mat = {{1,1,2},{3,3,4},{6,6,6}}, pat = {"ab","66"}
Output: {1,1}
Explanation: If we consider this mapping: "a" -> 3 and "b" -> 4; the submatrix with the upper-left corner (1,1) is a match as outlined in the matrix above.
Note that since the corresponding values of "a" and "b" must differ, the submatrix with the upper-left corner (1,0) is not a match. Hence, we return {1,1}.
Approach:
The main intuition here is that each distinct letter in the pat corresponds to a unique digit in the mat. This means we can think of the letters as placeholders for some digit. Our task is to find where in the mat we can match the structure of the pat, with each distinct letter mapping to a unique digit.
The approach is to iterate over each possible position in the mat that could be the upper-left corner of a matching submatrix. For each position, we check if we can map the letters in the pat to the digits in the mat such that the pat and the submatrix become identical. We use a map to store the current mappings of letters to digits, and a set to keep track of which digits are already used.
Steps-by-step approach:
- Iterate over possible starting positions:
- Loop through all possible starting positions for the pat in the mat.
- For each starting position:
- Call the matchPattern function to check if the pat matches at that position.
- If the pat matches, return the starting position.
- If no match is found, return {-1, -1}.
- In matchPattern(), Iterate over pat rows and columns:
- Loop through each row and column of the pat.
- For each character in the pat:
- If the character is a digit:
- Check if the corresponding value in the mat matches the digit.
- If the character is not a digit:
- Check if the character has been mapped to a value in the mat previously.
- If not, map the character to the corresponding value in the mat.
- If the character has been mapped to a different value, return false.
- If the character is a digit:
- If all characters in the pat match, return true.
Below is the implementation of the above approach:
#include <iostream>
#include <unordered_map>
#include <vector>
using namespace std;
// Function to check if the pat matches at a given
// starting position in the mat.
bool matchPattern(const vector<vector<int> >& mat,
const vector<string>& pat, int row,
int col)
{
const int m1 = mat.size(), n1 = mat[0].size(),
m2 = pat.size(), n2 = pat[0].length();
// Create a map to store the mapping between characters
// in the pat and their corresponding values in the
// mat.
unordered_map<char, int> charToValue;
// Iterate over the rows and columns of the pat.
for (int i = 0; i < m2; ++i) {
for (int j = 0; j < n2; ++j) {
const char c = pat[i][j];
const int v = mat[row + i][col + j];
// Check if the character is a digit.
if (isdigit(c)) {
// If the character is a digit, it must
// match the corresponding value in the
// mat.
if (c != v + '0') {
return false;
}
}
else {
// If the character is not a digit, it must
// have been mapped to a value in the mat
// previously.
if (charToValue.count(c)) {
// If the character has been mapped to a
// different value, it's a mismatch.
if (charToValue[c] != v) {
return false;
}
}
else {
// If the character has not been mapped
// before, map it to the current value.
charToValue[c] = v;
}
}
}
}
return true; // Return true if the pat matches at
// the given starting position.
}
vector<int> findPattern(vector<vector<int> >& mat,
vector<string>& pat)
{
const int m1 = mat.size(), n1 = mat[0].size(),
m2 = pat.size(), n2 = pat[0].length();
// Iterate over all possible starting positions for the
// pat in the mat.
for (int i = 0; i + m2 <= m1; ++i) {
for (int j = 0; j + n2 <= n1; ++j) {
// Check if the pat matches at the current
// starting position.
if (matchPattern(mat, pat, i, j)) {
return {
i, j
}; // Return the starting position if a
// match is found.
}
}
}
return { -1,
-1 }; // Return {-1, -1} if no match is found.
}
// Driver code
int main()
{
vector<vector<int> > mat
= { { 1, 2, 2 }, { 2, 2, 3 }, { 2, 3, 3 } };
vector<string> pat = { "ab", "bb" };
;
// Call the findPattern method to find the starting
// position of the pat in the mat.
vector<int> result = findPattern(mat, pat);
// Print the result.
cout << "Starting position of the pat: (" << result[0]
<< ", " << result[1] << ")" << endl;
return 0;
}
import java.util.*;
public class PatternMatching {
// Function to check if the pat matches at a given
// starting position in the mat.
public static boolean matchPattern(int[][] mat,
String[] pat,
int row, int col)
{
int m1 = mat.length, n1 = mat[0].length,
m2 = pat.length, n2 = pat[0].length();
// Create a map to store the mapping between
// characters in the pat and their corresponding
// values in the mat.
Map<Character, Integer> charToValue
= new HashMap<>();
// Iterate over the rows and columns of the pat.
for (int i = 0; i < m2; ++i) {
for (int j = 0; j < n2; ++j) {
char c = pat[i].charAt(j);
int v = mat[row + i][col + j];
// Check if the character is a digit.
if (Character.isDigit(c)) {
// If the character is a digit, it must
// match the corresponding value in the
// mat.
if (c != (char)(v + '0')) {
return false;
}
}
else {
// If the character is not a digit, it
// must have been mapped to a value in
// the mat previously.
if (charToValue.containsKey(c)) {
// If the character has been mapped
// to a different value, it's a
// mismatch.
if (charToValue.get(c) != v) {
return false;
}
}
else {
// If the character has not been
// mapped before, map it to the
// current value.
charToValue.put(c, v);
}
}
}
}
return true; // Return true if the pat matches at
// the given starting position.
}
public static int[] findPattern(int[][] mat,
String[] pat)
{
int m1 = mat.length, n1 = mat[0].length,
m2 = pat.length, n2 = pat[0].length();
// Iterate over all possible starting positions for
// the pat in the mat.
for (int i = 0; i + m2 <= m1; ++i) {
for (int j = 0; j + n2 <= n1; ++j) {
// Check if the pat matches at the current
// starting position.
if (matchPattern(mat, pat, i, j)) {
return new int[] {
i, j
}; // Return the starting position if a
// match is found.
}
}
}
return new int[] {
-1, -1
}; // Return {-1, -1} if no match is found.
}
// Driver code
public static void main(String[] args)
{
int[][] mat
= { { 1, 2, 2 }, { 2, 2, 3 }, { 2, 3, 3 } };
String[] pat = { "ab", "bb" };
// Call the findPattern method to find the starting
// position of the pat in the mat.
int[] result = findPattern(mat, pat);
// Print the result.
System.out.println("Starting position of the pat: ("
+ result[0] + ", " + result[1]
+ ")");
}
}
// This code is contributed by shivamgupta0987654321
def match_pattern(mat, pat, row, col):
m1, n1 = len(mat), len(mat[0])
m2, n2 = len(pat), len(pat[0])
# Create a map to store the mapping between characters
# in the pat and their corresponding values in the mat.
char_to_value = {}
# Iterate over the rows and columns of the pat.
for i in range(m2):
for j in range(n2):
c = pat[i][j]
v = mat[row + i][col + j]
# Check if the character is a digit.
if c.isdigit():
# If the character is a digit, it must
# match the corresponding value in the mat.
if c != str(v):
return False
else:
# If the character is not a digit, it must
# have been mapped to a value in the mat
# previously.
if c in char_to_value:
# If the character has been mapped to a
# different value, it's a mismatch.
if char_to_value[c] != v:
return False
else:
# If the character has not been mapped
# before, map it to the current value.
char_to_value[c] = v
# Return true if the pat matches at the given starting position.
return True
def find_pattern(mat, pat):
m1, n1 = len(mat), len(mat[0])
m2, n2 = len(pat), len(pat[0])
# Iterate over all possible starting positions for the pat in the mat.
for i in range(m1 - m2 + 1):
for j in range(n1 - n2 + 1):
# Check if the pat matches at the current starting position.
if match_pattern(mat, pat, i, j):
# Return the starting position if a match is found.
return [i, j]
return [-1, -1] # Return [-1, -1] if no match is found.
# Driver code
if __name__ == "__main__":
mat = [
[1, 2, 2],
[2, 2, 3],
[2, 3, 3]
]
pat = ["ab", "bb"]
# Call the find_pattern method to find the starting
# position of the pat in the mat.
result = find_pattern(mat, pat)
# Print the result.
print(f"Starting position of the pat: ({result[0]}, {result[1]})")
# This code is contributed by Ayush Mishra
// Function to check if the pat matches at a given
// starting position in the mat.
function matchPattern(mat, pat, row, col) {
const m1 = mat.length, n1 = mat[0].length,
m2 = pat.length, n2 = pat[0].length;
// Create a map to store the mapping between characters
// in the pat and their corresponding values in the mat.
const charToValue = new Map();
// Iterate over the rows and columns of the pat.
for (let i = 0; i < m2; ++i) {
for (let j = 0; j < n2; ++j) {
const c = pat[i][j];
const v = mat[row + i][col + j];
// Check if the character is a digit.
if (!isNaN(parseInt(c))) {
// If the character is a digit, it must
// match the corresponding value in the mat.
if (parseInt(c) !== v) {
return false;
}
} else {
// If the character is not a digit, it must
// have been mapped to a value in the mat
// previously.
if (charToValue.has(c)) {
// If the character has been mapped to a
// different value, it's a mismatch.
if (charToValue.get(c) !== v) {
return false;
}
} else {
// If the character has not been mapped
// before, map it to the current value.
charToValue.set(c, v);
}
}
}
}
return true; // Return true if the pat matches at
// the given starting position.
}
function findPattern(mat, pat) {
const m1 = mat.length, n1 = mat[0].length,
m2 = pat.length, n2 = pat[0].length;
// Iterate over all possible starting positions for the
// pat in the mat.
for (let i = 0; i + m2 <= m1; ++i) {
for (let j = 0; j + n2 <= n1; ++j) {
// Check if the pat matches at the current
// starting position.
if (matchPattern(mat, pat, i, j)) {
return [i, j]; // Return the starting position if a
// match is found.
}
}
}
return [-1, -1]; // Return [-1, -1] if no match is found.
}
// Driver code
const mat = [
[1, 2, 2],
[2, 2, 3],
[2, 3, 3]
];
const pat = ["ab", "bb"];
// Call the findPattern method to find the starting
// position of the pat in the mat.
const result = findPattern(mat, pat);
// Print the result.
console.log("Starting position of the pat: (" + result[0] + ", " + result[1] + ")");
// This code is contributed by Rambabu
Output
Starting position of the pat: (0, 0)
Time complexity: O(m1 * n1 * m2 * n2), m1, n1, m2, n2 are the lenghs and widths of the mat and the pat.
Auxiliary Space: O(1)