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;
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();
vector<int> duplicates = 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() {
children[0] = children[1] = NULL;
leaf = false;
}
};
bool insert(Trie*& head, vector<int>& row, int columns) {
Trie* curr = head;
for (int i = 0; i < columns; i++) {
// create a new node if path doesn't exist
if (curr->children[row[i]] == NULL)
curr->children[row[i]] = new Trie();
curr = curr->children[row[i]];
}
// row already exists in trie
if (curr->leaf)
return false;
// mark this path as a complete row
return (curr->leaf = true);
}
vector<int> repeatedRows(vector<vector<int>> &matrix, int rows, int columns) {
vector<int> result;
Trie* head = new Trie();
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();
vector<int> duplicates = 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];
Trie() {
children[0] = children[1] = null;
leaf = false;
}
}
static boolean insert(Trie head, int[] row, int columns) {
Trie curr = head;
for (int i = 0; i < columns; i++) {
// create a new node if path doesn't exist
if (curr.children[row[i]] == null)
curr.children[row[i]] = new Trie();
curr = curr.children[row[i]];
}
// row already exists in trie
if (curr.leaf)
return false;
// mark this path as a complete row
return (curr.leaf = true);
}
static ArrayList<Integer> repeatedRows(int[][] matrix, int rows, int columns) {
ArrayList<Integer> result = new ArrayList<>();
// create root of Trie
Trie head = new Trie();
for (int i = 0; i < rows; i++) {
// insert row and check for duplication
if (!insert(head, matrix[i], columns)) {
result.add(i);
}
}
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}
};
int rows = matrix.length;
int columns = matrix[0].length;
ArrayList<Integer> duplicates =
repeatedRows(matrix, rows, columns);
for (int idx : duplicates) {
System.out.print((idx + 1) + " ");
}
}
}
class Trie:
def __init__(self):
self.children = [None, None]
self.leaf = False
def insert(head, row, columns):
curr = head
for i in range(columns):
# create a new node if path doesn't exist
if curr.children[row[i]] is None:
curr.children[row[i]] = Trie()
curr = curr.children[row[i]]
# row already exists in trie
if curr.leaf:
return False
# mark this path as a complete row
curr.leaf = True
return True
def repeatedRows(matrix, rows, columns):
result = []
# create root of Trie
head = Trie()
for i in range(rows):
# insert row and check for duplication
if not insert(head, matrix[i], columns):
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;
class Trie {
public bool leaf;
public Trie[] children = new Trie[2];
public Trie() {
children[0] = children[1] = null;
leaf = false;
}
}
class GFG {
static bool insert(Trie head, int[] row, int columns)
{
Trie curr = head;
for (int i = 0; i < columns; i++) {
// create a new node if path doesn't exist
if (curr.children[row[i]] == null)
curr.children[row[i]] = new Trie();
curr = curr.children[row[i]];
}
// row already exists in trie
if (curr.leaf)
return false;
// mark this path as a complete row
curr.leaf = true;
return true;
}
static List<int> repeatedRows(int[][] matrix, int rows, int columns)
{
List<int> result = new List<int>();
// create root of Trie
Trie head = new Trie();
for (int i = 0; i < rows; i++) {
// insert row and check for duplication
if (!insert(head, matrix[i], columns)) {
result.Add(i);
}
}
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 },
};
int rows = matrix.Length;
int columns = matrix[0].Length;
List<int> duplicates =
repeatedRows(matrix, rows, columns);
foreach (int idx in duplicates) {
Console.Write((idx + 1) + " ");
}
}
}
class Trie {
leaf = false;
children = new Array(2).fill(null);
}
function insert(head, row, columns) {
let curr = head;
for (let i = 0; i < columns; i++) {
// create a new node if path doesn't exist
if (curr.children[row[i]] === null)
curr.children[row[i]] = new Trie();
curr = curr.children[row[i]];
}
// row already exists in trie
if (curr.leaf)
return false;
// mark this path as a complete row
curr.leaf = true;
return true;
}
function repeatedRows(matrix, rows, columns) {
const result = [];
// create root of Trie
let head = new Trie();
for (let i = 0; i < rows; i++) {
// insert row and check for duplication
if (!insert(head, matrix[i], columns)) {
result.push(i);
}
}
return result;
}
// Driver code
let 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],
];
let rows = matrix.length;
let columns = matrix[0].length;
let duplicates = repeatedRows(matrix, 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;
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();
vector<int> duplicates = 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