Skip to main content

2007 - Find Original Array From Doubled Array (Medium)

https://leetcode.com/problems/find-original-array-from-doubled-array/

Problem Statement

An integer array original is transformed into a doubled array changed by appending twice the value of every element in original, and then randomly shuffling the resulting array.

Given an array changed, return originalifchangedis a doubled array. Ifchangedis not a doubled array, return an empty array. The elements in original may be returned in any order.

Example 1:

Input: changed = [1,3,4,2,6,8]
Output: [1,3,4]
Explanation: One possible original array could be [1,3,4]:
- Twice the value of 1 is 1 * 2 = 2.
- Twice the value of 3 is 3 * 2 = 6.
- Twice the value of 4 is 4 * 2 = 8.
Other original arrays could be [4,3,1] or [3,1,4].

Example 2:

Input: changed = [6,3,0,1]
Output: []
Explanation: changed is not a doubled array.

Example 3:

Input: changed = [1]
Output: []
Explanation: changed is not a doubled array.

Constraints:

  • 1 <= changed.length <= 105
  • 0 <= changed[i] <= 105

Approach 1: Sorting + Hashmap

Written by @wingkwong
// Time Complexity: O(N + NlogN)
// Space Complexity: O(N)
// where N is the number of elements in `changed`
class Solution {
public:
// hashmap approach
vector<int> findOriginalArray(vector<int>& changed) {
// if the length of the input is odd, then return {}
// because doubled array must have even length
if (changed.size() & 1) return {};
// count the frequency of each number
unordered_map<int, int> m;
for (auto x: changed) m[x]++;
vector<int> ans;
// sort in ascending order
sort(changed.begin(), changed.end());
// keep the unique elements only in changed
// think of test cases like [0,0,0,0]
// alternatively you can handle it like
// - check if the frequency of 0 is odd, if so, return {}
// - push `0` `m[0] / 2` times to ans
changed.erase(unique(changed.begin(), changed.end()), changed.end());
// so that we can iterate `changed` from smallest to largest
for (auto x : changed) {
// if the number of m[x] is greater than than m[x * 2]
// then there would be some m[x] left
// therefore, return {} here as changed is not a doubled array
if (m[x] > m[x * 2]) return {};
for (int i = 0; i < m[x]; i++) {
// otherwise, we put the element `x` `m[x]` times to ans
ans.push_back(x);
// at the same time we decrease the count of m[x * 2] by 1
// we don't need to decrease m[x] by 1 as we won't use it again
m[x * 2] -= 1;
}
}
return ans;
}
};
// Time Complexity: O(N + KlogK)
// Space Complexity: O(N)
// where N is the number of elements in `changed`
// and K is the number of elements in `uniqueNumbers`
class Solution {
public:
// hashmap approach
vector<int> findOriginalArray(vector<int>& changed) {
// if the length of the input is odd, then return {}
// because doubled array must have even length
if (changed.size() & 1) return {};
// count the frequency of each number
unordered_map<int, int> m;
for (auto x: changed) m[x]++;
vector<int> ans;
vector<int> uniqueNumbers;
// push all unuque numbers to `uniqueNumbers`
for (auto x : m) uniqueNumbers.push_back(x.first);
// sort in ascending order
sort(uniqueNumbers.begin(), uniqueNumbers.end());
// so that we can iterate `changed` from smallest to largest
for (auto x : uniqueNumbers) {
// if the number of m[x] is greater than than m[x * 2]
// then there would be some m[x] left
// therefore, return {} here as changed is not a doubled array
if (m[x] > m[x * 2]) return {};
for (int i = 0; i < m[x]; i++) {
// otherwise, we put the element `x` `m[x]` times to ans
ans.push_back(x);
// at the same time we decrease the count of m[x * 2] by 1
// we don't need to decrease m[x] by 1 as we won't use it again
m[x * 2] -= 1;
}
}
return ans;
}
};
// Time Complexity: O(NlogN)
// Space Complexity: O(N)
// where N is the number of elements in `changed`
class Solution {
public:
// multiset approach
vector<int> findOriginalArray(vector<int>& changed) {
// if the length of the input is odd, then return {}
// because doubled array must have even length
if (changed.size() & 1) return {};
vector<int> ans;
// put all the elements to a multiset
multiset<int> s(changed.begin(), changed.end());
// keep doing the following logic when there is an element in the multiset
while (s.size()) {
// get the smallest element
int smallest = *s.begin();
ans.push_back(smallest);
// remove the smallest element in multiset
s.erase(s.begin());
// if the doubled value of smallest doesn't exist in the multiset
// then return {}
if (s.find(smallest * 2) == s.end()) return {};
// otherwise we can remove its doubled element
else s.erase(s.find(smallest * 2));
}
return ans;
}
};