Union of Two Sorted Arrays
Given two sorted arrays a[] and b[], where each array may contain duplicate elements, return the union of the two arrays in sorted order.
The union is the set of distinct elements that are present in either of the arrays.
Constraints:
1 <= a.size(), b.size() <= 10^5-10^9 <= a[i], b[i] <= 10^9
Brute Force
Put every value from both arrays into an ordered set. A set keeps only one copy of each value, and an ordered set keeps them sorted.
- Create an empty ordered set.
- Insert every value of
ainto the set. - Insert every value of
binto the set. - Copy the values from the set into the result, from smallest to largest.
This works, but it ignores that both arrays are already sorted. The set has to sort the values again, and it needs extra memory to hold them.
class Solution {public:vector<int> findUnion(vector<int>& a, vector<int>& b) {set<int> uniqueValues;for (int value : a) {uniqueValues.insert(value);}for (int value : b) {uniqueValues.insert(value);}vector<int> result;for (int value : uniqueValues) {result.push_back(value);}return result;}};
- Time: O((n + m) log(n + m)). Ordering the values costs O(log) per insert.
- Space: O(n + m). The set can hold every value.
Optimal Approach: Two Pointers
Both arrays are already sorted. So the smallest remaining value is always at the front of one of the two arrays. This is the same idea as merging two sorted lists, with one extra rule: skip duplicates.
We use:
i: pointer on arraya.j: pointer on arrayb.result: the union we are building.
The duplicate rule: before adding a value, check the last value in result. If it is the same, skip it. Because everything arrives in sorted order, any duplicate is always right next to its copy.
Steps:
- Start
i = 0andj = 0. - While both arrays have elements, pick the smaller of
a[i]andb[j]and move that pointer forward. - Add the picked value to
resultonly ifresultis empty or its last value is different. - When one array is finished, go through the rest of the other array with the same duplicate rule.
- Return
result.
class Solution {public:vector<int> findUnion(vector<int>& a, vector<int>& b) {int n = a.size();int m = b.size();int i = 0;int j = 0;vector<int> result;while (i < n && j < m) {int value;if (a[i] <= b[j]) {value = a[i];i++;} else {value = b[j];j++;}if (result.empty() || result.back() != value) {result.push_back(value);}}while (i < n) {if (result.empty() || result.back() != a[i]) {result.push_back(a[i]);}i++;}while (j < m) {if (result.empty() || result.back() != b[j]) {result.push_back(b[j]);}j++;}return result;}};
Complexity
Each step moves one pointer forward, so every element of both arrays is looked at exactly once.
Besides the output array, we only use the pointers i and j and one variable value. The output itself holds up to n + m values.