Given a binary matrix, the task is to find all unique rows of the given matrix in the order of their appearance in the matrix.
Examples:
Input: mat[][] = [[1 1 0 1],
[1 0 0 1],
[1 1 0 1]]
Output: [[1 1 0 1],
[1 0 0 1]]
Explanation: The two unique rows are R1: [1 1 0 1] and R2: [1 0 0 1].
As R1 first appeared at row-0 and R2 appeared at row-1, in the resulting list, R1 is kept before R2.Input: mat[][] = [[0 0 0 1],
[0 0 0 1]]
Output: [0 0 0 1]
Explanation: Only unique row is [0 0 0 1].
Table of Content
[Naive Approach] Row Comparison - O(n ^ 2 * m) Time and O(n * m) Space
The idea is to compare each row with all the unique rows found so far. If the row is not already present, add it to the result.
Working of Approach:
- Traverse the matrix row by row.
- Compare the current row with every row already present in res.
- If a matching row is found, skip it.
- Otherwise, add the current row to res.
- Since rows are processed in order, the first appearance order is maintained.
#include <iostream>
#include <vector>
using namespace std;
vector<vector<int>> uniqueRow(vector<vector<int>> &mat)
{
vector<vector<int>> res;
// Traverse each row of the matrix.
for (int i = 0; i < mat.size(); i++)
{
bool found = false;
// Compare the current row with unique rows.
for (auto &row : res)
{
if (row == mat[i])
{
found = true;
break;
}
}
// Add the row if it is not already present.
if (!found)
res.push_back(mat[i]);
}
return res;
}
int main()
{
vector<vector<int>> mat = {{1, 1, 0, 1}, {1, 0, 0, 1}, {1, 1, 0, 1}};
vector<vector<int>> res = uniqueRow(mat);
cout << "[";
for (int i = 0; i < res.size(); i++)
{
cout << "[";
for (int j = 0; j < res[i].size(); j++)
{
cout << res[i][j];
if (j + 1 < res[i].size())
cout << ", ";
}
cout << "]";
if (i + 1 < res.size())
cout << ", ";
}
cout << "]";
return 0;
}
import java.util.*;
class GFG {
public ArrayList<ArrayList<Integer> >
uniqueRow(int[][] mat)
{
ArrayList<ArrayList<Integer> > res
= new ArrayList<>();
// Traverse each row of the matrix.
for (int i = 0; i < mat.length; i++) {
boolean found = false;
// Compare the current row with unique rows.
for (ArrayList<Integer> row : res) {
boolean same = true;
for (int j = 0; j < mat[i].length; j++) {
if (row.get(j) != mat[i][j]) {
same = false;
break;
}
}
if (same) {
found = true;
break;
}
}
// Add the row if it is not already present.
if (!found) {
ArrayList<Integer> temp = new ArrayList<>();
for (int j = 0; j < mat[i].length; j++) {
temp.add(mat[i][j]);
}
res.add(temp);
}
}
return res;
}
public static void main(String[] args)
{
int[][] mat = { { 1, 1, 0, 1 },
{ 1, 0, 0, 1 },
{ 1, 1, 0, 1 } };
GFG obj = new GFG();
ArrayList<ArrayList<Integer> > res
= obj.uniqueRow(mat);
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.println("]");
}
}
def uniqueRow(mat):
res = []
# Traverse each row of the matrix.
for i in range(len(mat)):
found = False
# Compare the current row with unique rows.
for row in res:
if row == mat[i]:
found = True
break
# Add the row if it is not already present.
if not found:
res.append(mat[i])
return res
if __name__ == "__main__":
mat = [[1, 1, 0, 1], [1, 0, 0, 1], [1, 1, 0, 1]]
res = uniqueRow(mat)
print('[', end='')
for i in range(len(res)):
print('[', end='')
for j in range(len(res[i])):
print(res[i][j], end='')
if j + 1 < len(res[i]):
print(', ', end='')
print(']', end='')
if i + 1 < len(res):
print(', ', end='')
print(']')
using System;
using System.Collections.Generic;
class GFG {
public List<List<int> > uniqueRow(int[][] mat)
{
List<List<int> > res = new List<List<int> >();
// Traverse each row of the matrix.
for (int i = 0; i < mat.Length; i++) {
bool found = false;
// Compare the current row with unique rows.
foreach(List<int> row in res)
{
bool same = true;
for (int j = 0; j < mat[i].Length; j++) {
if (row[j] != mat[i][j]) {
same = false;
break;
}
}
if (same) {
found = true;
break;
}
}
// Add the row if it is not already present.
if (!found) {
List<int> temp = new List<int>();
for (int j = 0; j < mat[i].Length; j++) {
temp.Add(mat[i][j]);
}
res.Add(temp);
}
}
return res;
}
public static void Main()
{
int[][] mat = { new int[] { 1, 1, 0, 1 },
new int[] { 1, 0, 0, 1 },
new int[] { 1, 1, 0, 1 } };
GFG obj = new GFG();
List<List<int> > res = obj.uniqueRow(mat);
Console.Write("[");
for (int i = 0; i < res.Count; i++) {
Console.Write("[");
for (int j = 0; j < res[i].Count; j++) {
Console.Write(res[i][j]);
if (j + 1 < res[i].Count)
Console.Write(", ");
}
Console.Write("]");
if (i + 1 < res.Count)
Console.Write(", ");
}
Console.WriteLine("]");
}
}
function uniqueRow(mat)
{
let res = [];
// Traverse each row of the matrix.
for (let i = 0; i < mat.length; i++) {
let found = false;
// Compare the current row with unique rows.
for (let row of res) {
if (arraysEqual(row, mat[i])) {
found = true;
break;
}
}
// Add the row if it is not already present.
if (!found)
res.push(mat[i]);
}
return res;
}
function arraysEqual(a, b)
{
if (a === b)
return true;
if (a == null || b == null)
return false;
if (a.length !== b.length)
return false;
for (let i = 0; i < a.length; ++i) {
if (a[i] !== b[i])
return false;
}
return true;
}
// Driver Code
let mat =
[ [ 1, 1, 0, 1 ], [ 1, 0, 0, 1 ], [ 1, 1, 0, 1 ] ];
let res = uniqueRow(mat);
console.log("[");
for (let i = 0; i < res.length; i++) {
console.log("[");
for (let j = 0; j < res[i].length; j++) {
console.log(res[i][j]);
if (j + 1 < res[i].length)
console.log(", ");
}
console.log("]");
if (i + 1 < res.length)
console.log(", ");
}
console.log("]");
Output
[[1, 1, 0, 1], [1, 0, 0, 1]]
[Expected Approach] Hash Set and String Encoding - O(n * m * log n) Time and O(n * m) Space
The idea is to convert every row into a string and store it in a set. We then traverse the matrix again in its original order to identify and collect each unique row.
Working of Approach:
- Traverse every row and convert it into a string representation.
- Insert each string into a set to store the unique rows.
- Traverse the matrix again and create the string representation of each row.
- If the string is present in the set, add that row to the result and erase it.
- Erasing ensures that each unique row is added only once, while traversing the matrix in its original order maintains the order of appearance.
Let us understand with an example:
Input: mat[][] = [[1 1 0 1], [1 0 0 1], [1 1 0 1]]
- First row [1, 1, 0, 1] is converted to "1101" and inserted into the set.
- Second row [1, 0, 0, 1] is converted to "1001" and inserted into the set.
- Third row [1, 1, 0, 1] gives "1101", which is already present, so the set remains {"1001", "1101"}.
- In the second traversal, "1101" is found, added to vec, and erased from the set.
- "1001" is then found, added to vec, and erased. Hence, vec = [[1, 1, 0, 1], [1, 0, 0, 1]].
#include <iostream>
#include <vector>
#include <set>
#include <string>
using namespace std;
vector<vector<int>> uniqueRow(vector<vector<int>> &mat)
{
int row = mat.size();
int col = mat[0].size();
set<string> st;
vector<vector<int>> vec;
// Iterating over each row of the matrix.
for (int i = 0; i < row; i++)
{
string curr;
// Converting each row into a string.
for (int j = 0; j < col; j++)
{
curr += char('0' + mat[i][j]);
}
// Inserting the string representation of the row into the set.
st.insert(curr);
}
// Iterating over each row again.
for (int i = 0; i < row; i++)
{
string curr;
// Converting each row into a string.
for (int j = 0; j < col; j++)
{
curr += char('0' + mat[i][j]);
}
// Checking if present in set
if (st.find(curr) != st.end())
{
st.erase(curr);
vector<int> demo;
for (int j = 0; j < col; j++)
{
demo.push_back(mat[i][j]);
}
vec.push_back(demo);
}
}
return vec;
}
int main()
{
vector<vector<int>> mat = {{1, 1, 0, 1}, {1, 0, 0, 1}, {1, 1, 0, 1}};
vector<vector<int>> res = uniqueRow(mat);
cout << "[";
for (int i = 0; i < res.size(); i++)
{
cout << "[";
for (int j = 0; j < res[i].size(); j++)
{
cout << res[i][j];
if (j + 1 < res[i].size())
cout << ", ";
}
cout << "]";
if (i + 1 < res.size())
cout << ", ";
}
cout << "]";
return 0;
}
import java.util.*;
class GFG {
public ArrayList<ArrayList<Integer> >
uniqueRow(int[][] mat)
{
int row = mat.length;
int col = mat[0].length;
HashSet<String> st = new HashSet<>();
ArrayList<ArrayList<Integer> > vec
= new ArrayList<>();
// Iterating over each row of the matrix.
for (int i = 0; i < row; i++) {
StringBuilder curr = new StringBuilder();
// Converting each row into a string.
for (int j = 0; j < col; j++) {
curr.append((char)('0' + mat[i][j]));
}
// Inserting the string representation of the
// row into the set.
st.add(curr.toString());
}
// Iterating over each row again.
for (int i = 0; i < row; i++) {
StringBuilder curr = new StringBuilder();
// Converting each row into a string.
for (int j = 0; j < col; j++) {
curr.append((char)('0' + mat[i][j]));
}
// Checking if present in set
if (st.contains(curr.toString())) {
st.remove(curr.toString());
ArrayList<Integer> demo = new ArrayList<>();
for (int j = 0; j < col; j++) {
demo.add(mat[i][j]);
}
vec.add(demo);
}
}
return vec;
}
public static void main(String[] args)
{
int[][] mat = { { 1, 1, 0, 1 },
{ 1, 0, 0, 1 },
{ 1, 1, 0, 1 } };
GFG obj = new GFG();
ArrayList<ArrayList<Integer> > res
= obj.uniqueRow(mat);
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.println("]");
}
}
def uniqueRow(mat):
row = len(mat)
col = len(mat[0])
st = set()
vec = []
# Iterating over each row of the matrix.
for i in range(row):
curr = ''
# Converting each row into a string.
for j in range(col):
curr += chr(ord('0') + mat[i][j])
# Inserting the string representation of the row into the set.
st.add(curr)
# Iterating over each row again.
for i in range(row):
curr = ''
# Converting each row into a string.
for j in range(col):
curr += chr(ord('0') + mat[i][j])
# Checking if present in set
if curr in st:
st.remove(curr)
demo = []
for j in range(col):
demo.append(mat[i][j])
vec.append(demo)
return vec
if __name__ == '__main__':
mat = [[1, 1, 0, 1], [1, 0, 0, 1], [1, 1, 0, 1]]
res = uniqueRow(mat)
print('[', end='')
for i in range(len(res)):
print('[', end='')
for j in range(len(res[i])):
print(res[i][j], end='')
if j + 1 < len(res[i]):
print(', ', end='')
print(']', end='')
if i + 1 < len(res):
print(', ', end='')
print(']')
using System;
using System.Collections.Generic;
using System.Text;
class GFG {
public List<List<int> > uniqueRow(int[][] mat)
{
int row = mat.Length;
int col = mat[0].Length;
HashSet<string> st = new HashSet<string>();
List<List<int> > vec = new List<List<int> >();
// Iterating over each row of the matrix.
for (int i = 0; i < row; i++) {
StringBuilder curr = new StringBuilder();
// Converting each row into a string.
for (int j = 0; j < col; j++) {
curr.Append((char)('0' + mat[i][j]));
}
// Inserting the string representation of the
// row into the set.
st.Add(curr.ToString());
}
// Iterating over each row again.
for (int i = 0; i < row; i++) {
StringBuilder curr = new StringBuilder();
// Converting each row into a string.
for (int j = 0; j < col; j++) {
curr.Append((char)('0' + mat[i][j]));
}
// Checking if present in set
if (st.Contains(curr.ToString())) {
st.Remove(curr.ToString());
List<int> demo = new List<int>();
for (int j = 0; j < col; j++) {
demo.Add(mat[i][j]);
}
vec.Add(demo);
}
}
return vec;
}
public static void Main()
{
int[][] mat = { new int[] { 1, 1, 0, 1 },
new int[] { 1, 0, 0, 1 },
new int[] { 1, 1, 0, 1 } };
GFG obj = new GFG();
List<List<int> > res = obj.uniqueRow(mat);
Console.Write("[");
for (int i = 0; i < res.Count; i++) {
Console.Write("[");
for (int j = 0; j < res[i].Count; j++) {
Console.Write(res[i][j]);
if (j + 1 < res[i].Count)
Console.Write(", ");
}
Console.Write("]");
if (i + 1 < res.Count)
Console.Write(", ");
}
Console.WriteLine("]");
}
}
function uniqueRow(mat)
{
const row = mat.length;
const col = mat[0].length;
let st = new Set();
let vec = [];
// Iterating over each row of the matrix.
for (let i = 0; i < row; i++) {
let curr = "";
// Converting each row into a string.
for (let j = 0; j < col; j++) {
curr += String.fromCharCode("0".charCodeAt(0)
+ mat[i][j]);
}
// Inserting the string representation of the row
// into the set.
st.add(curr);
}
// Iterating over each row again.
for (let i = 0; i < row; i++) {
let curr = "";
// Converting each row into a string.
for (let j = 0; j < col; j++) {
curr += String.fromCharCode("0".charCodeAt(0)
+ mat[i][j]);
}
// Checking if present in set
if (st.has(curr)) {
st.delete(curr);
let demo = [];
for (let j = 0; j < col; j++) {
demo.push(mat[i][j]);
}
vec.push(demo);
}
}
return vec;
}
// Driver Code
const mat =
[ [ 1, 1, 0, 1 ], [ 1, 0, 0, 1 ], [ 1, 1, 0, 1 ] ];
const res = uniqueRow(mat);
console.log("[");
for (let i = 0; i < res.length; i++) {
console.log("[");
for (let j = 0; j < res[i].length; j++) {
console.log(res[i][j]);
if (j + 1 < res[i].length)
console.log(", ");
}
console.log("]");
if (i + 1 < res.length)
console.log(", ");
}
console.log("]");
Output
[[1, 1, 0, 1], [1, 0, 0, 1]]
[Alternate Approach] Trie - O(n * m) Time and O(n * m) Space
The idea is to insert each row into a Trie and mark the end of every new row. If the end node is already marked, the row is a duplicate.
Working of Approach:
- Create a Trie with two children for each node, one for 0 and one for 1.
- Traverse every row and insert its elements into the Trie.
- At the end of a row, check whether the node is already marked as an ending node. If it is not marked, mark it and add the row to the result.
#include <iostream>
#include <vector>
using namespace std;
class Node
{
public:
Node *child[2];
bool isEnd;
Node()
{
child[0] = child[1] = nullptr;
isEnd = false;
}
};
vector<vector<int>> uniqueRow(vector<vector<int>> &mat)
{
int row = mat.size();
int col = mat[0].size();
Node *root = new Node();
vector<vector<int>> res;
// Iterating over each row of the matrix.
for (int i = 0; i < row; i++)
{
Node *curr = root;
// Inserting the current row into the Trie.
for (int j = 0; j < col; j++)
{
int bit = mat[i][j];
// Creating a node if the path does not exist.
if (curr->child[bit] == nullptr)
curr->child[bit] = new Node();
curr = curr->child[bit];
}
// If the row is seen for the first time, add it.
if (!curr->isEnd)
{
curr->isEnd = true;
res.push_back(mat[i]);
}
}
return res;
}
int main()
{
vector<vector<int>> mat = {{1, 1, 0, 1}, {1, 0, 0, 1}, {1, 1, 0, 1}};
vector<vector<int>> res = uniqueRow(mat);
cout << "[";
for (int i = 0; i < res.size(); i++)
{
cout << "[";
for (int j = 0; j < res[i].size(); j++)
{
cout << res[i][j];
if (j + 1 < res[i].size())
cout << ", ";
}
cout << "]";
if (i + 1 < res.size())
cout << ", ";
}
cout << "]";
return 0;
}
import java.util.*;
class GFG {
class Node {
Node[] child = new Node[2];
boolean isEnd;
Node()
{
child[0] = child[1] = null;
isEnd = false;
}
}
public ArrayList<ArrayList<Integer> >
uniqueRow(int[][] mat)
{
int row = mat.length;
int col = mat[0].length;
Node root = new Node();
ArrayList<ArrayList<Integer> > res
= new ArrayList<>();
// Iterating over each row of the matrix.
for (int i = 0; i < row; i++) {
Node curr = root;
// Inserting the current row into the Trie.
for (int j = 0; j < col; j++) {
int bit = mat[i][j];
// Creating a node if the path does not
// exist.
if (curr.child[bit] == null)
curr.child[bit] = new Node();
curr = curr.child[bit];
}
// If the row is seen for the first time, add
// it.
if (!curr.isEnd) {
curr.isEnd = true;
ArrayList<Integer> temp = new ArrayList<>();
for (int j = 0; j < col; j++) {
temp.add(mat[i][j]);
}
res.add(temp);
}
}
return res;
}
public static void main(String[] args)
{
int[][] mat = { { 1, 1, 0, 1 },
{ 1, 0, 0, 1 },
{ 1, 1, 0, 1 } };
GFG obj = new GFG();
ArrayList<ArrayList<Integer> > res
= obj.uniqueRow(mat);
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.println("]");
}
}
class Node:
def __init__(self):
self.child = [None, None]
self.isEnd = False
def uniqueRow(mat):
row = len(mat)
col = len(mat[0])
root = Node()
res = []
# Iterating over each row of the matrix.
for i in range(row):
curr = root
# Inserting the current row into the Trie.
for j in range(col):
bit = mat[i][j]
# Creating a node if the path does not exist.
if curr.child[bit] is None:
curr.child[bit] = Node()
curr = curr.child[bit]
# If the row is seen for the first time, add it.
if not curr.isEnd:
curr.isEnd = True
res.append(mat[i])
return res
if __name__ == '__main__':
mat = [[1, 1, 0, 1], [1, 0, 0, 1], [1, 1, 0, 1]]
res = uniqueRow(mat)
print(res)
using System;
using System.Collections.Generic;
class GFG {
class Node {
public Node[] child = new Node[2];
public bool isEnd;
public Node()
{
child[0] = null;
child[1] = null;
isEnd = false;
}
}
public List<List<int> > uniqueRow(int[][] mat)
{
int row = mat.Length;
int col = mat[0].Length;
Node root = new Node();
List<List<int> > res = new List<List<int> >();
// Iterating over each row of the matrix.
for (int i = 0; i < row; i++) {
Node curr = root;
// Inserting the current row into the Trie.
for (int j = 0; j < col; j++) {
int bit = mat[i][j];
// Creating a node if the path does not
// exist.
if (curr.child[bit] == null)
curr.child[bit] = new Node();
curr = curr.child[bit];
}
// If the row is seen for the first time, add
// it.
if (!curr.isEnd) {
curr.isEnd = true;
List<int> temp = new List<int>();
for (int j = 0; j < col; j++) {
temp.Add(mat[i][j]);
}
res.Add(temp);
}
}
return res;
}
public static void Main()
{
int[][] mat = { new int[] { 1, 1, 0, 1 },
new int[] { 1, 0, 0, 1 },
new int[] { 1, 1, 0, 1 } };
GFG obj = new GFG();
List<List<int> > res = obj.uniqueRow(mat);
Console.Write("[");
for (int i = 0; i < res.Count; i++) {
Console.Write("[");
for (int j = 0; j < res[i].Count; j++) {
Console.Write(res[i][j]);
if (j + 1 < res[i].Count)
Console.Write(", ");
}
Console.Write("]");
if (i + 1 < res.Count)
Console.Write(", ");
}
Console.WriteLine("]");
}
}
class Node {
constructor()
{
this.child = [ null, null ];
this.isEnd = false;
}
}
function uniqueRow(mat)
{
let row = mat.length;
let col = mat[0].length;
let root = new Node();
let res = [];
// Iterating over each row of the matrix.
for (let i = 0; i < row; i++) {
let curr = root;
// Inserting the current row into the Trie.
for (let j = 0; j < col; j++) {
let bit = mat[i][j];
// Creating a node if the path does not exist.
if (curr.child[bit] === null)
curr.child[bit] = new Node();
curr = curr.child[bit];
}
// If the row is seen for the first time, add it.
if (!curr.isEnd) {
curr.isEnd = true;
res.push(mat[i]);
}
}
return res;
}
// Driver Code
let mat =
[ [ 1, 1, 0, 1 ], [ 1, 0, 0, 1 ], [ 1, 1, 0, 1 ] ];
let res = uniqueRow(mat);
console.log(res);
Output
[[1, 1, 0, 1], [1, 0, 0, 1]]