Given two sorted arrays nums1 and nums2, return an array that contains the union of these two arrays. The elements in the union must be in ascending order.
The union of two arrays is an array where all values are distinct and are present in either the first array, the second array, or both.
Input: nums1 = [1, 2, 3, 4, 5], nums2 = [1, 2, 7]
Output: [1, 2, 3, 4, 5, 7]
Explanation: The elements 1, 2 are common to both, 3, 4, 5 are from nums1 and 7 is from nums2
Input: nums1 = [3, 4, 6, 7, 9, 9], nums2 = [1, 5, 7, 8, 8]
Output: [1, 3, 4, 5, 6, 7, 8, 9]
Explanation: The element 7 is common to both, 3, 4, 6, 9 are from nums1 and 1, 5, 8 is from nums2
Input: nums1 = [3, 4, 4, 4], nums2 = [6, 7, 7]
The union of two arrays will be all the unique elements of both of the arrays combined. So, using a set data structure will help & can find the distinct elements because the set does not hold any duplicates. As it is mandatory to preserve the order of the elements, use an ordered set.
s
to store all the unique elements and a vector or list union
to store the final answer. #include <bits/stdc++.h>
using namespace std;
class Solution {
public:
vector<int> unionArray(vector<int>& nums1, vector<int>& nums2) {
// Using unordered for storing unique elements
set<int> s;
vector<int> Union;
// Insert all elements of nums1 into the set
for (int num : nums1) {
s.insert(num);
}
// Insert all elements of nums2 into the set
for (int num : nums2) {
s.insert(num);
}
// Convert the set to vector to get the union
for (int num : s) {
Union.push_back(num);
}
return Union;
}
};
int main() {
// Initialize the arrays
vector<int> nums1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
vector<int> nums2 = {2, 3, 4, 4, 5, 11, 12};
// Create an instance of the Solution class
Solution finder;
/* Get the union of nums1 and
nums2 using the class method*/
vector<int> Union = finder.unionArray(nums1, nums2);
// Output the result
cout << "Union of nums1 and nums2 is:" << endl;
for (int val : Union) {
cout << val << " ";
}
cout << endl;
return 0;
}
import java.util.*;
class Solution {
public int[] unionArray(int[] nums1, int[] nums2) {
Set<Integer> set = new TreeSet<>();
// Insert all elements of nums1 into the set
for (int num : nums1) {
set.add(num);
}
// Insert all elements of nums2 into the set
for (int num : nums2) {
set.add(num);
}
// Convert the set to an integer array to get the union
int[] union = new int[set.size()];
int index = 0;
for (int num : set) {
union[index++] = num;
}
return union;
}
public static void main(String[] args) {
// Initialize the arrays
int[] nums1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int[] nums2 = {2, 3, 4, 4, 5, 11, 12};
// Create an instance of the Solution class
Solution finder = new Solution();
/* Get the union of nums1 and
nums2 using the class method */
int[] union = finder.unionArray(nums1, nums2);
System.out.println("Union of nums1 and nums2 is:");
for (int val : union) {
System.out.print(val + " ");
}
System.out.println();
}
}
from typing import List
class Solution:
def unionArray(self, nums1, nums2):
# Using set for storing unique elements
s = set()
Union = []
# Insert all elements of nums1 into the set
for num in nums1:
s.add(num)
# Insert all elements of nums2 into the set
for num in nums2:
s.add(num)
# Convert the set to list to get the union
for num in sorted(s): # Sorting for union of sorted arrays
Union.append(num)
return Union
if __name__ == "__main__":
# Initialize the arrays (lists in Python)
nums1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
nums2 = [2, 3, 4, 4, 5, 11, 12]
# Create an instance of the Solution class
finder = Solution()
""" Get the union of nums1 and
nums2 using the class method"""
union = finder.unionArray(nums1, nums2)
print("Union of nums1 and nums2 is:")
print(" ".join(map(str, union)))
class Solution {
unionArray(nums1, nums2) {
// Using Set for storing unique elements
let set = new Set();
let union = [];
// Insert all elements of nums1 into the set
for (let num of nums1) {
set.add(num);
}
// Insert all elements of nums2 into the set
for (let num of nums2) {
set.add(num);
}
/* Convert the set to an array and sort
it to get the union in ascending order */
union = Array.from(set).sort((a, b) => a - b);
return union;
}
}
// Main function to test the Solution class
const nums1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const nums2 = [2, 3, 4, 4, 5, 11, 12];
// Create an instance of the Solution class
const finder = new Solution();
/* Get the union of nums1 and
nums2 using the class method*/
const union = finder.unionArray(nums1, nums2);
console.log("Union of nums1 and nums2 is:");
console.log(union.join(" "));
The optimal approach uses the two-pointers to solve the problem. Use two pointers, one for each array, and traverse both arrays simultaneously. Keep adding the smaller element between the two arrays to the result vector if it hasn't been added already.
If both elements are equal, add any one of them, ensuring that all unique elements are added in sorted order.
i
to iterate nums1 and j
to iterate nums2 as 0.
#include <bits/stdc++.h>
using namespace std;
class Solution {
public:
vector<int> unionArray(vector<int>& nums1, vector<int>& nums2) {
vector<int> Union; // Vector to store the union elements
int i = 0, j = 0;
int n = nums1.size();
int m = nums2.size();
while (i < n && j < m) {
// Case 1 and 2
if (nums1[i] <= nums2[j]){
if (Union.size() == 0 || Union.back() != nums1[i])
Union.push_back(nums1[i]);
i++;
}
//case 3
else{
if (Union.size() == 0 || Union.back() != nums2[j])
Union.push_back(nums2[j]);
j++;
}
}
// If any element left in arr1
while (i < n){
if (Union.back() != nums1[i])
Union.push_back(nums1[i]);
i++;
}
// If any elements left in arr2
while (j < m){
if (Union.back() != nums2[j])
Union.push_back(nums2[j]);
j++;
}
return Union;
}
};
int main() {
vector<int> nums1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
vector<int> nums2 = {2, 3, 4, 4, 5, 11, 12};
// Create an instance of the Solution class
Solution finder;
// Get union of nums1 and nums2 using class method
vector<int> Union = finder.unionArray(nums1, nums2);
cout << "Union of nums1 and nums2 is:" << endl;
for (int val : Union) {
cout << val << " ";
}
cout << endl;
return 0;
}
import java.util.*;
class Solution {
public int[] unionArray(int[] nums1, int[] nums2) {
List<Integer> UnionList = new ArrayList<>();
int i = 0, j = 0;
int n = nums1.length;
int m = nums2.length;
while (i < n && j < m) {
// Case 1 and 2
if (nums1[i] <= nums2[j]) {
if (UnionList.isEmpty() || UnionList.get(UnionList.size() - 1) != nums1[i]) {
UnionList.add(nums1[i]);
}
i++;
}
// Case 3
else {
if (UnionList.isEmpty() || UnionList.get(UnionList.size() - 1) != nums2[j]) {
UnionList.add(nums2[j]);
}
j++;
}
}
// Add remaining elements of nums1, if any
while (i < n) {
if (UnionList.isEmpty() || UnionList.get(UnionList.size() - 1) != nums1[i]) {
UnionList.add(nums1[i]);
}
i++;
}
// Add remaining elements of nums2, if any
while (j < m) {
if (UnionList.isEmpty() || UnionList.get(UnionList.size() - 1) != nums2[j]) {
UnionList.add(nums2[j]);
}
j++;
}
// Convert List<Integer> to int[]
int[] Union = new int[UnionList.size()];
for (int k = 0; k < UnionList.size(); k++) {
Union[k] = UnionList.get(k);
}
return Union;
}
public static void main(String[] args) {
int[] nums1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int[] nums2 = {2, 3, 4, 4, 5, 11, 12};
// Create an instance of the Solution class
Solution finder = new Solution();
// Get union of nums1 and nums2 using class method
int[] Union = finder.unionArray(nums1, nums2);
// Output the result
System.out.println("Union of nums1 and nums2 is:");
for (int val : Union) {
System.out.print(val + " ");
}
System.out.println();
}
}
from typing import List
class Solution:
def unionArray(self, nums1: List[int], nums2: List[int]) -> List[int]:
union = []#union set
i, j = 0, 0
n, m = len(nums1), len(nums2)
while i < n and j < m:
#case 1 and 2
if nums1[i] <= nums2[j]:
if not union or union[-1] != nums1[i]:
union.append(nums1[i])
i += 1
#case 3
else:
if not union or union[-1] != nums2[j]:
union.append(nums2[j])
j += 1
#if any elements left in nums1
while i < n:
if not union or union[-1] != nums1[i]:
union.append(nums1[i])
i += 1
#if any elements left in nums2
while j < m:
if not union or union[-1] != nums2[j]:
union.append(nums2[j])
j += 1
return union
def main(self):
nums1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
nums2 = [2, 3, 4, 4, 5, 11, 12]
# Create an instance of the Solution class
finder = Solution()
# Get union of nums1 and nums2 using class method
union = finder.unionArray(nums1, nums2)
print("Union of nums1 and nums2 is:")
print(union)
if __name__ == "__main__":
Solution().main()
class Solution {
unionArray(nums1, nums2) {
// Array to store the union elements
let union = [];
let i = 0, j = 0;
let n = nums1.length;
let m = nums2.length;
while (i < n && j < m) {
// Case 1 and 2
if (nums1[i] <= nums2[j]) {
if (union.length === 0 || union[union.length - 1] !== nums1[i]) {
union.push(nums1[i]);
}
i++;
// Case 3
} else {
if (union.length === 0 || union[union.length - 1] !== nums2[j]) {
union.push(nums2[j]);
}
j++;
}
}
// Add remaining elements of nums1, if any
while (i < n) {
if (union.length === 0 || union[union.length - 1] !== nums1[i]) {
union.push(nums1[i]);
}
i++;
}
// Add remaining elements of nums2, if any
while (j < m) {
if (union.length === 0 || union[union.length - 1] !== nums2[j]) {
union.push(nums2[j]);
}
j++;
}
return union;
}
main() {
const nums1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const nums2 = [2, 3, 4, 4, 5, 11, 12];
// Create an instance of the Solution class
const finder = new Solution();
// Get union of nums1 and nums2 using class method
const union = finder.unionArray(nums1, nums2);
console.log("Union of nums1 and nums2 is:");
console.log(union);
}
}
// Execute the main method if this script is run directly
if (require.main === module) {
new Solution().main();
}
Q: Why do we need both merging and deduplication?
A: Merging ensures that elements from both arrays are included in the result in sorted order. Deduplication ensures that repeated elements (either within a single array or across both arrays) appear only once in the final result.
Q: What if the arrays are very large?
A: For very large arrays: If they fit in memory, use the two-pointer approach to merge them efficiently. If they don’t fit in memory, use external sorting techniques or divide the arrays into manageable chunks, process each chunk separately, and merge the results.
Q: How would you handle unsorted input arrays?
A: If the input arrays are unsorted: Sort each array first O(mlogm) and O(nlogn)). Apply the two-pointer approach or merge logic. This approach would have an overall time complexity of O(mlogm+nlogn+m+n).
Q: How would you extend this to handle k sorted arrays?
A: To handle k sorted arrays: Use a min-heap to merge the arrays. Push the smallest element of each array into the heap. Extract the minimum element, add it to the result, and push the next element from the same array into the heap. This has a time complexity of O(Nlogk), where N is the total number of elements.