Given two sorted arrays a[] and b[], the task is to return union of both the arrays in sorted order. Union of two arrays is an array having all distinct elements that are present in either array. The input arrays may contain duplicates.
Examples:
Input: a[] = {1, 1, 2, 2, 2, 4}, b[] = {2, 2, 4, 4}
Output: {1, 2, 4}
Explanation: 1, 2 and 4 are the distinct elements present in either array.Input: a[] = {3, 5, 10, 10, 10, 15, 15, 20}, b[] = {5, 10, 10, 15, 30}
Output: {3, 5, 10, 15, 20, 30}
Explanation: 3, 5, 10, 15, 20 and 30 are the distinct elements present in either array.
Table of Content
[Naive Approach] Using Nested Loops – O(n*m) Time and O(1) Space
The intuition behind this approach is to gather unique elements from two arrays by checking each element against the current result array.
The idea is to traverse both the arrays and for each element, check if the element is present in the result or not. If not, then add this element to the result.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
vector<int> findUnion(vector<int>& a, vector<int>& b) {
vector<int> res;
// Traverse through a[] and search every element
// a[i] in result
for(int i = 0; i < a.size(); i++){
// check if the element is already
// in the result to avoid duplicates
int j;
for (j = 0; j < res.size(); j++) {
if (res[j] == a[i])
break;
}
if (j == res.size())
res.push_back(a[i]);
}
// Traverse through b[] and search every element
// b[i] in result
for(int i = 0; i < b.size(); i++){
// check if the element is already
// in the result to avoid duplicates
int j;
for (j = 0; j < res.size(); j++) {
if (res[j] == b[i])
break;
}
if (j == res.size())
res.push_back(b[i]);
}
sort(res.begin(), res.end());
return res;
}
int main() {
vector<int> a = {1, 1, 2, 2, 2, 4};
vector<int> b = {2, 2, 4, 4};
vector<int> res = findUnion(a, b);
for (int i = 0; i < res.size(); i++)
cout << res[i] << " ";
return 0;
}
#include <stdio.h>
#include <stdlib.h>
// Function to compare two integers for qsort
int compare(const void* a, const void* b) {
return (*(int*)a - *(int*)b);
}
int* findUnion(int a[], int n, int b[], int m, int* size) {
int* res = (int*)malloc((m + n) * sizeof(int));
int index = 0;
// Traverse through a[] and search every element
// a[i] in result
for (int i = 0; i < n; i++) {
// Check if the element is already in the result to avoid duplicates
int j;
for (j = 0; j < index; j++) {
if (res[j] == a[i])
break;
}
if (j == index)
res[index++] = a[i];
}
// Traverse through b[] and search every element
// b[i] in result
for (int i = 0; i < m; i++) {
// Check if the element is already in the result to avoid duplicates
int j;
for (j = 0; j < index; j++) {
if (res[j] == b[i])
break;
}
if (j == index)
res[index++] = b[i];
}
// Sort the result array using qsort
qsort(res, index, sizeof(int), compare);
*size = index;
return res;
}
int main() {
int a[] = {1, 1, 2, 2, 2, 4};
int b[] = {2, 2, 4, 4};
int n = sizeof(a) / sizeof(a[0]);
int m = sizeof(b) / sizeof(b[0]);
int size;
int* result = findUnion(a, n, b, m, &size);
for (int i = 0; i < size; i++)
printf("%d ", result[i]);
free(result);
return 0;
}
import java.util.*;
class GFG {
static ArrayList<Integer> findUnion(int[] a, int[] b) {
ArrayList<Integer> res = new ArrayList<>();
// Traverse through a[] and search every element
// a[i] in result
for (int i = 0; i < a.length; i++) {
// check if the element is already in the result
// to avoid duplicates
if (!res.contains(a[i])) {
res.add(a[i]);
}
}
// Traverse through b[] and search every element
// b[i] in result
for (int i = 0; i < b.length; i++) {
// check if the element is already in the result
// to avoid duplicates
if (!res.contains(b[i])) {
res.add(b[i]);
}
}
Collections.sort(res);
return res;
}
public static void main(String[] args) {
int[] a = {1, 1, 2, 2, 2, 4};
int[] b = {2, 2, 4, 4};
ArrayList<Integer> res = findUnion(a, b);
for (Integer num : res) {
System.out.print(num + " ");
}
}
}
def findUnion(a, b):
res = []
# Traverse through a[] and search every element
# a[i] in result
for i in range(len(a)):
# check if the element is already
# in the result to avoid duplicates
if a[i] not in res:
res.append(a[i])
# Traverse through b[] and search every element
# b[i] in result
for i in range(len(b)):
# check if the element is already
# in the result to avoid duplicates
if b[i] not in res:
res.append(b[i])
res.sort()
return res
if __name__ == "__main__":
a = [1, 1, 2, 2, 2, 4]
b = [2, 2, 4, 4]
res = findUnion(a, b)
for i in res:
print(i, end=" ")
using System;
using System.Collections.Generic;
class GFG {
static List<int> findUnion(int[] a, int[] b) {
List<int> res = new List<int>();
// Traverse through a[] and search every element
// a[i] in result
for (int i = 0; i < a.Length; i++) {
// check if the element is already
// in the result to avoid duplicates
if (!res.Contains(a[i])) {
res.Add(a[i]);
}
}
// Traverse through b[] and search every element
// b[i] in result
for (int i = 0; i < b.Length; i++) {
// check if the element is already
// in the result to avoid duplicates
if (!res.Contains(b[i])) {
res.Add(b[i]);
}
}
res.Sort();
return res;
}
static void Main() {
int[] a = {1, 1, 2, 2, 2, 4};
int[] b = {2, 2, 4, 4};
List<int> res = findUnion(a, b);
foreach (int i in res) {
Console.Write(i + " ");
}
}
}
function findUnion(a, b) {
let res = [];
// Traverse through a[] and search every element
// a[i] in result
for (let i = 0; i < a.length; i++) {
// check if the element is already
// in the result to avoid duplicates
if (!res.includes(a[i])) {
res.push(a[i]);
}
}
// Traverse through b[] and search every element
// b[i] in result
for (let i = 0; i < b.length; i++) {
// check if the element is already
// in the result to avoid duplicates
if (!res.includes(b[i])) {
res.push(b[i]);
}
}
res.sort((x, y) => x - y);
return res;
}
// Driver code
const a = [1, 1, 2, 2, 2, 4];
const b = [2, 2, 4, 4];
const res = findUnion(a, b);
console.log(res.join(" "));
Output
1 2 4
Time Complexity: O((n + m)2), where n is size of a[] and m is size of b[]
- Copying all elements from a[] to res[] takes O(n2) time.
- Now in the worst case, there will be no common elements in a[] and b[]. So, to check if the first element of b[] is present in res[], we need n comparisons. Similarly, for second element of b[], we need (n + 1) comparisons. So for m elements, total number of comparisons will be: n + (n + 1) + (n + 2) …. (n + m) = (n * m) + (m2 / 2)
- So, overall time complexity = O(n2 + n * m + m2)
Auxiliary Space: O(1)
[Better Approach] Using Set – O((n+m)*(log (n+m))) Time and O(n+m) Space
The approach is to insert all elements from both arrays, a[] and b[], into a set.
Since a set automatically removes duplicates, it gives us the union of the two arrays.
Also, the set keeps the elements in sorted order, so after inserting them, we can store these sorted and unique elements in a result array.
Note: In Python and JavaScript, the set data structure does not store the elements in sorted order, so we need to explicitly sort the union array.
#include <iostream>
#include <set>
#include <vector>
using namespace std;
vector<int> findUnion(vector<int> &a, vector<int> &b) {
set<int> st;
// Put all elements of a[] in st
for (int i = 0; i < a.size(); i++)
st.insert(a[i]);
// Put all elements of b[] in st
for (int i = 0; i < b.size(); i++)
st.insert(b[i]);
vector<int> res;
// iterate through the set to fill the result array
for (auto it : st)
res.push_back(it);
return res;
}
int main() {
vector<int> a = {1, 1, 2, 2, 2, 4};
vector<int> b = {2, 2, 4, 4};
vector<int> res = findUnion(a, b);
for (int i = 0; i < res.size(); i++)
cout << res[i] << " ";
return 0;
}
import java.util.*;
class GFG {
static ArrayList<Integer> findUnion(int a[],
int b[]) {
Set<Integer> st = new TreeSet<>();
// Put all elements of a[] in st
for (int i = 0; i < a.length; i++)
st.add(a[i]);
// Put all elements of b[] in st
for (int i = 0; i < b.length; i++)
st.add(b[i]);
ArrayList<Integer> res = new ArrayList<>(st);
return res;
}
public static void main(String[] args) {
int a[] = { 1, 1, 2, 2, 2, 4 };
int b[] = { 2, 2, 4, 4 };
ArrayList<Integer> res = findUnion(a, b);
for (int i = 0; i < res.size(); i++)
System.out.print(res.get(i) + " ");
}
}
def findUnion(a, b):
st = set()
# Put all elements of a[] in st
for i in range(len(a)):
st.add(a[i])
# Put all elements of b[] in st
for i in range(len(b)):
st.add(b[i])
res = []
# iterate through the set to fill the result array
for it in st:
res.append(it)
res.sort()
return res
if __name__ == "__main__":
a = [1, 1, 2, 2, 2, 4]
b = [2, 2, 4, 4]
res = findUnion(a, b)
for i in res:
print(i, end=" ")
using System;
using System.Collections.Generic;
class GFG {
static List<int> findUnion(int[] a, int[] b) {
SortedSet<int> st = new SortedSet<int>();
// Put all elements of a[] in st
for (int i = 0; i < a.Length; i++)
st.Add(a[i]);
// Put all elements of b[] in st
for (int i = 0; i < b.Length; i++)
st.Add(b[i]);
List<int> res = new List<int>(st);
return res;
}
static void Main() {
int[] a = {1, 1, 2, 2, 2, 4};
int[] b = {2, 2, 4, 4};
List<int> res = findUnion(a, b);
for (int i = 0; i < res.Count; i++)
Console.Write(res[i] + " ");
}
}
function findUnion(a, b) {
let st = new Set();
// Put all elements of a[] in st
for (let i = 0; i < a.length; i++)
st.add(a[i]);
// Put all elements of b[] in st
for (let i = 0; i < b.length; i++)
st.add(b[i]);
let res = Array.from(st);
res.sort((x, y) => x - y);
return res;
}
//Driver code
let a = [1, 1, 2, 2, 2, 4];
let b = [2, 2, 4, 4];
let res = findUnion(a, b);
console.log(res.join(" "));
Output
1 2 4
Time Complexity: O((n + m) * (log (n + m))) , where n is the size of array a[] and m is the size of array b[]
Auxiliary Space: O(n + m)
[Expected Approach] Using Merge Step of Merge Sort - O(n+m) Time and O(1) Space
Since both arrays are sorted, we can traverse them simultaneously using two pointers.
At each step, we process the smaller element (or one if both are equal), allowing us to build the union in sorted order while easily skipping duplicates.
- Initialize two pointers for the arrays and an empty result array.
- Traverse both arrays simultaneously.
- Add the smaller element to the result and move its pointer forward.
- If both elements are equal, add it once and move both pointers forward.
- Skip duplicate elements while traversing.
- Append the remaining elements of the unfinished array, skipping duplicates.
#include <bits/stdc++.h>
using namespace std;
vector<int> findUnion(vector<int>& a, vector<int>& b) {
vector<int> res;
int n = a.size();
int m = b.size();
// This is similar to merge of merge sort
int i = 0, j = 0;
while(i < n && j < m) {
// Skip duplicate elements in the first array
if(i > 0 && a[i - 1] == a[i]) {
i++;
continue;
}
// Skip duplicate elements in the second array
if(j > 0 && b[j - 1] == b[j]) {
j++;
continue;
}
// select and add the smaller element and move
if(a[i] < b[j]) {
res.push_back(a[i]);
i++;
}
else if(a[i] > b[j]) {
res.push_back(b[j]);
j++;
}
// If equal, then add to result and move both
else {
res.push_back(a[i]);
i++;
j++;
}
}
// Add the remaining elements of a[]
while (i < n) {
// Skip duplicate elements in the first array
if(i > 0 && a[i - 1] == a[i]) {
i++;
continue;
}
res.push_back(a[i]);
i++;
}
// Add the remaining elements of b[]
while (j < m) {
// Skip duplicate elements in the second array
if(j > 0 && b[j - 1] == b[j]) {
j++;
continue;
}
res.push_back(b[j]);
j++;
}
return res;
}
int main() {
vector<int> a = {1, 1, 2, 2, 2, 4};
vector<int> b = {2, 2, 4, 4};
vector<int> res = findUnion(a, b);
for (int x : res) {
cout << x << " ";
}
}
#include <stdio.h>
int* findUnion(int a[], int n, int b[], int m, int* size) {
int* res = (int*)malloc((m + n) * sizeof(int));
int i = 0, j = 0;
int index = 0;
// This is similar to merge of merge sort
while (i < n && j < m) {
// Skip duplicate elements in the first array
if (i > 0 && a[i - 1] == a[i]) {
i++;
continue;
}
// Skip duplicate elements in the second array
if (j > 0 && b[j - 1] == b[j]) {
j++;
continue;
}
// select and add the smaller element and move
if (a[i] < b[j]) {
res[index++] = a[i];
i++;
}
else if (a[i] > b[j]) {
res[index++] = b[j];
j++;
}
// If equal, then add to result and move both
else {
res[index++] = a[i];
i++;
j++;
}
}
// Add the remaining elements of a[]
while (i < n) {
// Skip duplicate elements in the first array
if (i > 0 && a[i - 1] == a[i]) {
i++;
continue;
}
res[index++] = a[i];
i++;
}
// Add the remaining elements of b[]
while (j < m) {
// Skip duplicate elements in the second array
if (j > 0 && b[j - 1] == b[j]) {
j++;
continue;
}
res[index++] = b[j];
j++;
}
// Update the size of the result
*size = index;
return res;
}
int main() {
int a[] = {1, 1, 2, 2, 2, 4};
int b[] = {2, 2, 4, 4};
int n = sizeof(a) / sizeof(a[0]);
int m = sizeof(b) / sizeof(b[0]);
int size;
int* result = findUnion(a, n, b, m, &size);
// Print the result
for (int i = 0; i < size; i++) {
printf("%d ", result[i]);
}
free(result);
return 0;
}
import java.util.*;
class GFG {
static ArrayList<Integer> findUnion(int[] a, int[] b) {
ArrayList<Integer> res = new ArrayList<>();
int n = a.length;
int m = b.length;
// This is similar to merge of merge sort
int i = 0, j = 0;
while(i < n && j < m) {
// Skip duplicate elements in the first array
if(i > 0 && a[i - 1] == a[i]) {
i++;
continue;
}
// Skip duplicate elements in the second array
if(j > 0 && b[j - 1] == b[j]) {
j++;
continue;
}
// select and add the smaller element and move
if(a[i] < b[j]) {
res.add(a[i]);
i++;
}
else if(a[i] > b[j]) {
res.add(b[j]);
j++;
}
// If equal, then add to result and move both
else {
res.add(a[i]);
i++;
j++;
}
}
// Add the remaining elements of a[]
while (i < n) {
// Skip duplicate elements in the first array
if(i > 0 && a[i - 1] == a[i]) {
i++;
continue;
}
res.add(a[i]);
i++;
}
// Add the remaining elements of b[]
while (j < m) {
// Skip duplicate elements in the second array
if(j > 0 && b[j - 1] == b[j]) {
j++;
continue;
}
res.add(b[j]);
j++;
}
return res;
}
public static void main(String[] args) {
int[] a = {1, 1, 2, 2, 2, 4};
int[] b = {2, 2, 4, 4};
List<Integer> res = findUnion(a, b);
for (int x : res) {
System.out.print(x + " ");
}
}
}
def findUnion(a, b):
res = []
n, m = len(a), len(b)
i, j = 0, 0
# This is similar to merge of merge sort
while i < n and j < m:
# Skip duplicate elements in the first array
if i > 0 and a[i - 1] == a[i]:
i += 1
continue
# Skip duplicate elements in the second array
if j > 0 and b[j - 1] == b[j]:
j += 1
continue
# select and add the smaller element and move
if a[i] < b[j]:
res.append(a[i])
i += 1
elif a[i] > b[j]:
res.append(b[j])
j += 1
# If equal, then add to result and move both
else:
res.append(a[i])
i += 1
j += 1
# Add the remaining elements of a[]
while i < n:
# Skip duplicate elements in the first array
if i > 0 and a[i - 1] == a[i]:
i += 1
continue
res.append(a[i])
i += 1
# Add the remaining elements of b[]
while j < m:
# Skip duplicate elements in the second array
if j > 0 and b[j - 1] == b[j]:
j += 1
continue
res.append(b[j])
j += 1
return res
if __name__ == "__main__":
a = [1, 1, 2, 2, 2, 4]
b = [2, 2, 4, 4]
res = findUnion(a, b)
for x in res:
print(x ,end = " ");
using System;
using System.Collections.Generic;
class GFG {
static List<int> findUnion(int[] a, int[] b) {
List<int> res = new List<int>();
int n = a.Length;
int m = b.Length;
// This is similar to merge of merge sort
int i = 0, j = 0;
while (i < n && j < m) {
// Skip duplicate elements in the first array
if (i > 0 && a[i - 1] == a[i]) {
i++;
continue;
}
// Skip duplicate elements in the second array
if (j > 0 && b[j - 1] == b[j]) {
j++;
continue;
}
// select and add the smaller element and move
if (a[i] < b[j]) {
res.Add(a[i]);
i++;
}
else if (a[i] > b[j]) {
res.Add(b[j]);
j++;
}
// If equal, then add to result and move both
else {
res.Add(a[i]);
i++;
j++;
}
}
// Add the remaining elements of a[]
while (i < n) {
// Skip duplicate elements in the first array
if (i > 0 && a[i - 1] == a[i]) {
i++;
continue;
}
res.Add(a[i]);
i++;
}
// Add the remaining elements of b[]
while (j < m) {
// Skip duplicate elements in the second array
if (j > 0 && b[j - 1] == b[j]) {
j++;
continue;
}
res.Add(b[j]);
j++;
}
return res;
}
static void Main() {
int[] a = { 1, 1, 2, 2, 2, 4 };
int[] b = { 2, 2, 4, 4 };
List<int> res = findUnion(a, b);
foreach (int x in res) {
Console.Write(x + " ");
}
}
}
function findUnion(a, b) {
let res = [];
let n = a.length, m = b.length;
let i = 0, j = 0;
// This is similar to merge of merge sort
while(i < n && j < m) {
// Skip duplicate elements in the first array
if(i > 0 && a[i - 1] === a[i]) {
i++;
continue;
}
// Skip duplicate elements in the second array
if(j > 0 && b[j - 1] === b[j]) {
j++;
continue;
}
// select and add the smaller element and move
if(a[i] < b[j]) {
res.push(a[i]);
i++;
} else if(a[i] > b[j]) {
res.push(b[j]);
j++;
}
// If equal, then add to result and move both
else {
res.push(a[i]);
i++;
j++;
}
}
// Add the remaining elements of a[]
while(i < n) {
// Skip duplicate elements in the first array
if(i > 0 && a[i - 1] === a[i]) {
i++;
continue;
}
res.push(a[i]);
i++;
}
// Add the remaining elements of b[]
while(j < m) {
// Skip duplicate elements in the second array
if(j > 0 && b[j - 1] === b[j]) {
j++;
continue;
}
res.push(b[j]);
j++;
}
return res;
}
// Driver code
let a = [1, 1, 2, 2, 2, 4];
let b = [2, 2, 4, 4];
console.log(findUnion(a, b).join(" "));
Output
1 2 4
Time Complexity: O(n + m), Where n is the size of a[] and m is the size of b[]
Auxiliary Space: O(1)
Related Articles: