Given a binary matrix mat[][], print the rows which are duplicates of rows that are already present in the matrix.
Examples:
Input: mat[][] = [[1, 1, 0, 1, 0, 1],
[0, 0, 1, 0, 0, 1],
[1, 0, 1, 1, 0, 0],
[1, 1, 0, 1, 0, 1],
[0, 0, 1, 0, 0, 1],
[0, 0, 1, 0, 0, 1]]
Output: [4, 5, 6]
Explanation: Row at index 4 is same as 0. Rows at indexes 5 and 6 are same as index 1
Table of Content
[Naive Approach] Traverse All Rows - O((m^2)*n) Time and O(1) Space
For each row, check if it already exists by scanning all previous rows.
#include <iostream>
#include <vector>
using namespace std;
class Solution {
public:
vector<int> repeatedRows(vector<vector<int>> &matrix, int rows, int columns) {
vector<int> result;
for (int i = 0; i < rows; i++) {
bool found = false;
for (int j = 0; j < i; j++) {
int k = 0;
// check if all elements of both rows are equal or not
for (k = 0; k < columns; k++) {
if (matrix[i][k] != matrix[j][k])
break;
}
// all elements matched -> duplicate row found
if (k == columns) {
found = true;
break;
}
}
// store index of duplicate row
if (found) {
result.push_back(i);
}
}
return result;
}
};
int main() {
vector<vector<int>> matrix = {
{1, 1, 0, 1, 0, 1},
{0, 0, 1, 0, 0, 1},
{1, 0, 1, 1, 0, 0},
{1, 1, 0, 1, 0, 1},
{0, 0, 1, 0, 0, 1},
{0, 0, 1, 0, 0, 1}
};
int rows = matrix.size();
int columns = matrix[0].size();
Solution obj;
vector<int> duplicates = obj.repeatedRows(matrix, rows, columns);
for (int idx : duplicates) {
cout << idx + 1 << " ";
}
return 0;
}
import java.util.ArrayList;
public class GFG {
public static ArrayList<Integer>
repeatedRows(ArrayList<ArrayList<Integer>> matrix,
int rows, int columns)
{
ArrayList<Integer> result = new ArrayList<>();
for (int i = 0; i < rows; i++) {
boolean found = false;
for (int j = 0; j < i; j++) {
int k = 0;
// check if all elements of both rows are equal or not
for (k = 0; k < columns; k++) {
if (!matrix.get(i).get(k)
.equals(matrix.get(j).get(k)))
break;
}
// all elements matched -> duplicate row found
if (k == columns) {
found = true;
break;
}
}
// store index of duplicate row
if (found) {
result.add(i);
}
}
return result;
}
public static void main(String[] args)
{
ArrayList<ArrayList<Integer>> matrix
= new ArrayList<>();
matrix.add(new ArrayList<Integer>() {{
add(1); add(1); add(0); add(1); add(0); add(1);
}});
matrix.add(new ArrayList<Integer>() {{
add(0); add(0); add(1); add(0); add(0); add(1);
}});
matrix.add(new ArrayList<Integer>() {{
add(1); add(0); add(1); add(1); add(0); add(0);
}});
matrix.add(new ArrayList<Integer>() {{
add(1); add(1); add(0); add(1); add(0); add(1);
}});
matrix.add(new ArrayList<Integer>() {{
add(0); add(0); add(1); add(0); add(0); add(1);
}});
matrix.add(new ArrayList<Integer>() {{
add(0); add(0); add(1); add(0); add(0); add(1);
}});
int rows = matrix.size();
int columns = matrix.get(0).size();
ArrayList<Integer> duplicates =
repeatedRows(matrix, rows, columns);
for (int idx : duplicates) {
System.out.print((idx + 1) + " ");
}
}
}
def repeatedRows(matrix, rows, columns):
result = []
for i in range(rows):
found = False
for j in range(i):
k = 0
# check if all elements of both rows are equal or not
while k < columns:
if matrix[i][k] != matrix[j][k]:
break
k += 1
# all elements matched -> duplicate row found
if k == columns:
found = True
break
# store index of duplicate row
if found:
result.append(i)
return result
if __name__ == "__main__":
matrix = [[1, 1, 0, 1, 0, 1],
[0, 0, 1, 0, 0, 1],
[1, 0, 1, 1, 0, 0],
[1, 1, 0, 1, 0, 1],
[0, 0, 1, 0, 0, 1],
[0, 0, 1, 0, 0, 1]]
rows = len(matrix)
columns = len(matrix[0])
duplicates = repeatedRows(matrix, rows, columns)
for idx in duplicates:
print(idx + 1, end=" ")
using System;
using System.Collections.Generic;
public class GFG {
public static List<int>
repeatedRows(List<List<int>> matrix, int rows, int columns)
{
List<int> result = new List<int>();
for (int i = 0; i < rows; i++) {
bool found = false;
for (int j = 0; j < i; j++) {
int k = 0;
// check if all elements of both rows are equal or not
for (k = 0; k < columns; k++) {
if (matrix[i][k] != matrix[j][k])
break;
}
// all elements matched -> duplicate row found
if (k == columns) {
found = true;
break;
}
}
// store index of duplicate row
if (found) {
result.Add(i);
}
}
return result;
}
public static void Main()
{
List<List<int>> matrix = new List<List<int>>{
new List<int>{ 1, 1, 0, 1, 0, 1 },
new List<int>{ 0, 0, 1, 0, 0, 1 },
new List<int>{ 1, 0, 1, 1, 0, 0 },
new List<int>{ 1, 1, 0, 1, 0, 1 },
new List<int>{ 0, 0, 1, 0, 0, 1 },
new List<int>{ 0, 0, 1, 0, 0, 1 }
};
int rows = matrix.Count;
int columns = matrix[0].Count;
List<int> duplicates =
repeatedRows(matrix, rows, columns);
foreach (int idx in duplicates) {
Console.Write((idx + 1) + " ");
}
}
}
function repeatedRows(matrix, rows, columns) {
const result = [];
for (let i = 0; i < rows; i++) {
let found = false;
for (let j = 0; j < i; j++) {
let k = 0;
// check if all elements of both rows are equal or not
while (k < columns) {
if (matrix[i][k] !== matrix[j][k]) {
break;
}
k++;
}
// all elements matched -> duplicate row found
if (k === columns) {
found = true;
break;
}
}
// store index of duplicate row
if (found) {
result.push(i);
}
}
return result;
}
// Driver code
const matrix = [
[1, 1, 0, 1, 0, 1],
[0, 0, 1, 0, 0, 1],
[1, 0, 1, 1, 0, 0],
[1, 1, 0, 1, 0, 1],
[0, 0, 1, 0, 0, 1],
[0, 0, 1, 0, 0, 1]
];
const rows = matrix.length;
const columns = matrix[0].length;
const duplicates = repeatedRows(matrix, rows, columns);
for (let idx of duplicates) {
console.log(idx + 1);
}
Output
4 5 6
[Expected Approach-1] Using Trie - O(m*n) Time and O(m*n) Space
A Trie is used to efficiently store rows of the binary matrix since each row contains only 0 and 1. Each row is inserted as a path in the Trie. If the path already exists and the final node is marked as a leaf, the row is identified as a duplicate, otherwise the row is inserted and the end node is marked.
#include <iostream>
#include <vector>
using namespace std;
struct Trie {
bool leaf;
Trie* children[2];
};
Trie* getNewTrieNode() {
Trie* node = new Trie;
node->children[0] = node->children[1] = NULL;
node->leaf = false;
return node;
}
bool insert(Trie*& head, vector<int>& row, int columns) {
Trie* curr = head;
for (int i = 0; i < columns; i++) {
if (curr->children[row[i]] == NULL)
curr->children[row[i]] = getNewTrieNode();
curr = curr->children[row[i]];
}
// row already exists in trie
if (curr->leaf)
return false;
return (curr->leaf = true);
}
class Solution {
public:
vector<int> repeatedRows(vector<vector<int>> &matrix, int rows, int columns) {
vector<int> result;
Trie* head = getNewTrieNode();
for (int i = 0; i < rows; i++) {
// insert row and check for duplication
if (!insert(head, matrix[i], columns)) {
result.push_back(i);
}
}
return result;
}
};
int main() {
vector<vector<int>> matrix = {
{1, 1, 0, 1, 0, 1},
{0, 0, 1, 0, 0, 1},
{1, 0, 1, 1, 0, 0},
{1, 1, 0, 1, 0, 1},
{0, 0, 1, 0, 0, 1},
{0, 0, 1, 0, 0, 1}
};
int rows = matrix.size();
int columns = matrix[0].size();
Solution obj;
vector<int> duplicates = obj.repeatedRows(matrix, rows, columns);
for (int idx : duplicates) {
cout << idx + 1 << " ";
}
return 0;
}
import java.util.ArrayList;
class GFG {
static class Trie {
boolean leaf;
Trie[] children = new Trie[2];
}
static Trie getNewTrieNode() {
Trie node = new Trie();
node.children[0] = null;
node.children[1] = null;
node.leaf = false;
return node;
}
static boolean insert(Trie head, int[] arr, int columns) {
Trie curr = head;
for (int i = 0; i < columns; i++) {
if (curr.children[arr[i]] == null)
curr.children[arr[i]] = getNewTrieNode();
curr = curr.children[arr[i]];
}
// row already exists in trie
if (curr.leaf)
return false;
return (curr.leaf = true);
}
static ArrayList<Integer> repeatedRows(int[][] mat, int rows, int columns) {
ArrayList<Integer> result = new ArrayList<>();
Trie head = getNewTrieNode();
for (int i = 0; i < rows; i++) {
// insert row and check for duplication
if (!insert(head, mat[i], columns)) {
result.add(i);
}
}
return result;
}
public static void main(String[] args) {
int[][] mat = {
{1, 1, 0, 1, 0, 1},
{0, 0, 1, 0, 0, 1},
{1, 0, 1, 1, 0, 0},
{1, 1, 0, 1, 0, 1},
{0, 0, 1, 0, 0, 1},
{0, 0, 1, 0, 0, 1}
};
int rows = mat.length;
int columns = mat[0].length;
ArrayList<Integer> duplicates =
repeatedRows(mat, rows, columns);
for (int idx : duplicates) {
System.out.print((idx + 1) + " ");
}
}
}
class Trie:
def __init__(self):
self.leaf = False
self.children = [None, None]
def getNewTrieNode():
return Trie()
def insert(head, arr, columns):
curr = head
for i in range(columns):
if curr.children[arr[i]] is None:
curr.children[arr[i]] = getNewTrieNode()
curr = curr.children[arr[i]]
# row already exists in trie
if curr.leaf:
return False
curr.leaf = True
return True
def repeatedRows(mat, rows, columns):
result = []
head = getNewTrieNode()
for i in range(rows):
# insert row and check for duplication
if not insert(head, mat[i], columns):
result.append(i)
return result
if __name__ == "__main__":
mat = [
[1, 1, 0, 1, 0, 1],
[0, 0, 1, 0, 0, 1],
[1, 0, 1, 1, 0, 0],
[1, 1, 0, 1, 0, 1],
[0, 0, 1, 0, 0, 1],
[0, 0, 1, 0, 0, 1],
]
rows = len(mat)
columns = len(mat[0])
duplicates = repeatedRows(mat, rows, columns)
for idx in duplicates:
print(idx + 1, end=" ")
using System;
using System.Collections.Generic;
class Trie {
public bool leaf;
public Trie[] children = new Trie[2];
}
class GFG {
static Trie getNewTrieNode()
{
return new Trie();
}
static bool insert(Trie head, int[] arr, int columns)
{
Trie curr = head;
for (int i = 0; i < columns; i++) {
if (curr.children[arr[i]] == null)
curr.children[arr[i]] = getNewTrieNode();
curr = curr.children[arr[i]];
}
// row already exists in trie
if (curr.leaf)
return false;
curr.leaf = true;
return true;
}
static List<int> repeatedRows(int[][] mat, int rows, int columns)
{
List<int> result = new List<int>();
Trie head = getNewTrieNode();
for (int i = 0; i < rows; i++) {
// insert row and check for duplication
if (!insert(head, mat[i], columns)) {
result.Add(i);
}
}
return result;
}
public static void Main(string[] args)
{
int[][] mat = {
new int[] { 1, 1, 0, 1, 0, 1 },
new int[] { 0, 0, 1, 0, 0, 1 },
new int[] { 1, 0, 1, 1, 0, 0 },
new int[] { 1, 1, 0, 1, 0, 1 },
new int[] { 0, 0, 1, 0, 0, 1 },
new int[] { 0, 0, 1, 0, 0, 1 },
};
int rows = mat.Length;
int columns = mat[0].Length;
List<int> duplicates =
repeatedRows(mat, rows, columns);
foreach (int idx in duplicates) {
Console.Write((idx + 1) + " ");
}
}
}
class Trie {
constructor() {
this.leaf = false;
this.children = new Array(2).fill(null);
}
}
function getNewTrieNode() {
return new Trie();
}
function insert(head, arr, columns) {
let curr = head;
for (let i = 0; i < columns; i++) {
if (curr.children[arr[i]] === null)
curr.children[arr[i]] = getNewTrieNode();
curr = curr.children[arr[i]];
}
// row already exists in trie
if (curr.leaf)
return false;
curr.leaf = true;
return true;
}
function repeatedRows(mat, rows, columns) {
const result = [];
let head = getNewTrieNode();
for (let i = 0; i < rows; i++) {
// insert row and check for duplication
if (!insert(head, mat[i], columns)) {
result.push(i);
}
}
return result;
}
// Driver code
let mat = [
[1, 1, 0, 1, 0, 1],
[0, 0, 1, 0, 0, 1],
[1, 0, 1, 1, 0, 0],
[1, 1, 0, 1, 0, 1],
[0, 0, 1, 0, 0, 1],
[0, 0, 1, 0, 0, 1],
];
let rows = mat.length;
let columns = mat[0].length;
let duplicates = repeatedRows(mat, rows, columns);
for (let idx of duplicates) {
console.log(idx + 1);
}
Output
4 5 6
[Expected Approach-2] Using a hash set of rows as strings: O(m*n) Time and O(m*n) Space
Use a hash set to store string representations of each row, allowing for quick lookup and comparison. By iterating through the rows and concatenating their elements into strings, then checks for duplicate strings in the hash set. If a duplicate is found, the index of the corresponding row is added to a result array.
#include <iostream>
#include <vector>
#include <unordered_set>
using namespace std;
class Solution {
public:
vector<int> repeatedRows(vector<vector<int>> &matrix, int rows, int columns) {
vector<int> result;
unordered_set<string> seen;
for (int i = 0; i < rows; i++) {
string temp = "";
// build string representation of current row
for (int j = 0; j < columns; j++) {
temp += to_string(matrix[i][j]);
}
// row already exists in set
if (seen.find(temp) != seen.end()) {
result.push_back(i);
}
else {
seen.insert(temp);
}
}
return result;
}
};
int main() {
vector<vector<int>> matrix = {
{1, 1, 0, 1, 0, 1},
{0, 0, 1, 0, 0, 1},
{1, 0, 1, 1, 0, 0},
{1, 1, 0, 1, 0, 1},
{0, 0, 1, 0, 0, 1},
{0, 0, 1, 0, 0, 1}
};
int rows = matrix.size();
int columns = matrix[0].size();
Solution obj;
vector<int> duplicates = obj.repeatedRows(matrix, rows, columns);
for (int idx : duplicates) {
cout << idx + 1 << " ";
}
return 0;
}
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class GFG {
public static List<Integer> repeatedRows(int[][] matrix) {
List<Integer> result = new ArrayList<>();
Set<String> seen = new HashSet<>();
for (int i = 0; i < matrix.length; i++) {
StringBuilder temp = new StringBuilder();
// build string representation of current row
for (int j = 0; j < matrix[0].length; j++) {
temp.append(matrix[i][j]);
}
String rowString = temp.toString();
// row already exists in set
if (seen.contains(rowString)) {
result.add(i);
}
else {
seen.add(rowString);
}
}
return result;
}
public static void main(String[] args) {
int[][] matrix = {
{1, 1, 0, 1, 0, 1},
{0, 0, 1, 0, 0, 1},
{1, 0, 1, 1, 0, 0},
{1, 1, 0, 1, 0, 1},
{0, 0, 1, 0, 0, 1},
{0, 0, 1, 0, 0, 1}
};
List<Integer> duplicates = repeatedRows(matrix);
for (int idx : duplicates) {
System.out.print((idx + 1) + " ");
}
}
}
def repeatedRows(matrix):
result = []
seen = set()
for i, row in enumerate(matrix):
# build string representation of current row
row_str = ''.join(map(str, row))
# row already exists in set
if row_str in seen:
result.append(i)
else:
seen.add(row_str)
return result
if __name__ == "__main__":
matrix = [
[1, 1, 0, 1, 0, 1],
[0, 0, 1, 0, 0, 1],
[1, 0, 1, 1, 0, 0],
[1, 1, 0, 1, 0, 1],
[0, 0, 1, 0, 0, 1],
[0, 0, 1, 0, 0, 1],
]
duplicates = repeatedRows(matrix)
for idx in duplicates:
print(idx + 1, end=" ")
using System;
using System.Collections.Generic;
class GFG {
static List<int> repeatedRows(int[][] matrix)
{
List<int> result = new List<int>();
HashSet<string> seen = new HashSet<string>();
for (int i = 0; i < matrix.Length; i++) {
string temp = "";
// build string representation of current row
for (int j = 0; j < matrix[0].Length; j++) {
temp += matrix[i][j];
}
// row already exists in set
if (seen.Contains(temp)) {
result.Add(i);
}
else {
seen.Add(temp);
}
}
return result;
}
public static void Main(string[] args)
{
int[][] matrix = {
new int[] { 1, 1, 0, 1, 0, 1 },
new int[] { 0, 0, 1, 0, 0, 1 },
new int[] { 1, 0, 1, 1, 0, 0 },
new int[] { 1, 1, 0, 1, 0, 1 },
new int[] { 0, 0, 1, 0, 0, 1 },
new int[] { 0, 0, 1, 0, 0, 1 }
};
List<int> duplicates = repeatedRows(matrix);
foreach (int idx in duplicates) {
Console.Write((idx + 1) + " ");
}
}
}
function repeatedRows(matrix) {
const result = [];
const seen = new Set();
for (let i = 0; i < matrix.length; i++) {
let temp = '';
// build string representation of current row
for (let j = 0; j < matrix[0].length; j++) {
temp += matrix[i][j];
}
// row already exists in set
if (seen.has(temp)) {
result.push(i);
} else {
seen.add(temp);
}
}
return result;
}
// Driver Code
const matrix = [
[1, 1, 0, 1, 0, 1],
[0, 0, 1, 0, 0, 1],
[1, 0, 1, 1, 0, 0],
[1, 1, 0, 1, 0, 1],
[0, 0, 1, 0, 0, 1],
[0, 0, 1, 0, 0, 1]
];
const result = repeatedRows(matrix);
for (let idx of result) {
console.log(idx + 1);
}
Output
4 5 6