2570. Merge Two 2D Arrays by Summing Values
Problem Description
You are given two 2D integer arrays nums1
and nums2
. Each array contains pairs of [id, value]
where:
- The
id
represents a unique identifier for a number - The
value
represents the value associated with thatid
Both input arrays are sorted in ascending order by id
, and within each array, all id
s are unique.
Your task is to merge these two arrays into a single array following these rules:
-
Include all unique ids: If an
id
appears in eithernums1
ornums2
(or both), it should appear in the result. -
Sum the values: For each
id
in the result:- If the
id
exists in both arrays, its value should be the sum of values from both arrays - If the
id
exists in only one array, use that array's value (treat the missing value as 0)
- If the
-
Maintain sorted order: The resulting array must be sorted in ascending order by
id
. -
No duplicates: Each
id
should appear exactly once in the result.
For example, if nums1 = [[1,2], [3,4]]
and nums2 = [[1,3], [2,5]]
:
id
1 appears in both arrays with values 2 and 3, so the result has[1, 5]
(2+3)id
2 appears only innums2
with value 5, so the result has[2, 5]
id
3 appears only innums1
with value 4, so the result has[3, 4]
- Final result:
[[1,5], [2,5], [3,4]]
Intuition
When we need to merge two arrays and sum values for matching ids, the key insight is that we're essentially performing a grouping operation - we want to group all values by their id
and sum them up.
Since both arrays are already sorted by id
, we could use a two-pointer approach to traverse both arrays simultaneously. However, there's an even simpler approach: we can treat this as a counting problem.
Think of it this way - we don't really care which array a particular [id, value]
pair came from. What matters is:
- What are all the unique
id
s across both arrays? - What's the total sum of values for each
id
?
This naturally leads us to use a hash table (or Counter in Python) where:
- The key is the
id
- The value is the running sum of all values associated with that
id
We can simply iterate through both arrays (we can even concatenate them since we don't care about their origin), and for each [id, value]
pair, we add the value to our counter for that id
. This automatically handles:
- Merging values when an
id
appears in both arrays (they get summed) - Including ids that appear in only one array (they just get counted once)
- Eliminating duplicate ids (the counter naturally groups by key)
Finally, since we need the result sorted by id
, we can simply sort the counter items by their keys. Python's sorted()
function on dictionary items naturally sorts by the first element of each tuple (which is the id
), giving us exactly what we need.
This approach is elegant because it reduces a seemingly complex merge operation to a simple counting problem, leveraging the properties of hash tables to handle all the merging logic automatically.
Learn more about Two Pointers patterns.
Solution Approach
The solution uses a counting approach with a hash table to merge the two arrays efficiently.
Step-by-step implementation:
-
Initialize a Counter: We create a
Counter
object (which is a specialized dictionary in Python) to store the sum of values for eachid
.cnt = Counter()
-
Combine and iterate through both arrays: Instead of processing the arrays separately, we concatenate them using
nums1 + nums2
. This creates a single list containing all[id, value]
pairs from both arrays.for i, v in nums1 + nums2: cnt[i] += v
For each pair
[i, v]
wherei
is the id andv
is the value:- If
i
already exists in the counter, we addv
to its current sum - If
i
doesn't exist, the Counter automatically initializes it to 0 and then addsv
- If
-
Convert to sorted result: After processing all pairs,
cnt
contains each uniqueid
as a key with its total sum as the value. We convert this to the required format:return sorted(cnt.items())
cnt.items()
returns pairs of(id, total_value)
sorted()
sorts these pairs by the first element (theid
) in ascending order- The result is a list of lists in the format
[[id1, sum1], [id2, sum2], ...]
Why this works:
- The Counter automatically handles merging: if an
id
appears multiple times (whether in the same array or across both arrays), all its values get summed - No special logic needed for ids that appear in only one array - they're simply added once
- The final sort ensures the output meets the ascending order requirement
Time Complexity: O((m + n) log(m + n))
where m
and n
are the lengths of the two arrays. The iteration takes O(m + n)
time, and sorting the unique ids takes O(k log k)
where k
is the number of unique ids (at most m + n
).
Space Complexity: O(m + n)
for storing the counter with all unique ids.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a small example to illustrate the solution approach.
Given:
nums1 = [[1,2], [3,4]]
nums2 = [[1,3], [2,5]]
Step 1: Initialize a Counter
cnt = Counter() # Initially empty: {}
Step 2: Process the concatenated arrays
We iterate through nums1 + nums2 = [[1,2], [3,4], [1,3], [2,5]]
-
First pair
[1,2]
:id=1, value=2
cnt[1] += 2
- Counter becomes:
{1: 2}
-
Second pair
[3,4]
:id=3, value=4
cnt[3] += 4
- Counter becomes:
{1: 2, 3: 4}
-
Third pair
[1,3]
:id=1, value=3
cnt[1] += 3
(adds to existing value)- Counter becomes:
{1: 5, 3: 4}
-
Fourth pair
[2,5]
:id=2, value=5
cnt[2] += 5
- Counter becomes:
{1: 5, 3: 4, 2: 5}
Step 3: Convert to sorted result
cnt.items()
gives us:[(1, 5), (3, 4), (2, 5)]
sorted(cnt.items())
sorts by the first element (id):[(1, 5), (2, 5), (3, 4)]
- This converts to the final result:
[[1, 5], [2, 5], [3, 4]]
Result verification:
id=1
appeared in both arrays with values 2 and 3, summed to 5 βid=2
appeared only innums2
with value 5 βid=3
appeared only innums1
with value 4 β- Result is sorted by id in ascending order β
Solution Implementation
1class Solution:
2 def mergeArrays(
3 self, nums1: List[List[int]], nums2: List[List[int]]
4 ) -> List[List[int]]:
5 # Create a Counter dictionary to store id-value pairs
6 id_value_counter = Counter()
7
8 # Combine both arrays and iterate through all [id, value] pairs
9 combined_arrays = nums1 + nums2
10 for id_num, value in combined_arrays:
11 # Accumulate values for the same id
12 id_value_counter[id_num] += value
13
14 # Convert counter items to list and sort by id (key)
15 # items() returns tuples of (id, total_value)
16 result = sorted(id_value_counter.items())
17
18 return result
19```
20
21Note: The code requires the following import at the top of the file:
22```python3
23from collections import Counter
24from typing import List
25
1class Solution {
2 public int[][] mergeArrays(int[][] nums1, int[][] nums2) {
3 // Create a counter array to store sum of values for each id (0-1000)
4 int[] counter = new int[1001];
5
6 // Accumulate values from first array
7 // Each element is [id, value] pair
8 for (int[] pair : nums1) {
9 counter[pair[0]] += pair[1];
10 }
11
12 // Accumulate values from second array
13 for (int[] pair : nums2) {
14 counter[pair[0]] += pair[1];
15 }
16
17 // Count how many unique ids have non-zero values
18 int resultSize = 0;
19 for (int id = 0; id < 1001; id++) {
20 if (counter[id] > 0) {
21 resultSize++;
22 }
23 }
24
25 // Create result array with exact size needed
26 int[][] result = new int[resultSize][2];
27
28 // Populate result array with [id, sum] pairs in ascending order
29 int resultIndex = 0;
30 for (int id = 0; id < 1001; id++) {
31 if (counter[id] > 0) {
32 result[resultIndex] = new int[] {id, counter[id]};
33 resultIndex++;
34 }
35 }
36
37 return result;
38 }
39}
40
1class Solution {
2public:
3 vector<vector<int>> mergeArrays(vector<vector<int>>& nums1, vector<vector<int>>& nums2) {
4 // Array to store the sum of values for each ID (0 to 1000)
5 int idValueSum[1001]{};
6
7 // Accumulate values from the first array
8 // Each element is [id, value]
9 for (auto& element : nums1) {
10 idValueSum[element[0]] += element[1];
11 }
12
13 // Accumulate values from the second array
14 // Each element is [id, value]
15 for (auto& element : nums2) {
16 idValueSum[element[0]] += element[1];
17 }
18
19 // Build the result array with non-zero sums
20 vector<vector<int>> result;
21 for (int id = 0; id < 1001; ++id) {
22 if (idValueSum[id] != 0) {
23 // Add [id, sum] pair to the result
24 result.push_back({id, idValueSum[id]});
25 }
26 }
27
28 return result;
29 }
30};
31
1/**
2 * Merges two 2D arrays by summing values with the same ID.
3 * Each input array contains pairs of [id, value].
4 * Returns a sorted array of [id, sum] pairs where sum is the total of all values for that id.
5 *
6 * @param nums1 - First array of [id, value] pairs
7 * @param nums2 - Second array of [id, value] pairs
8 * @returns Merged array with aggregated values, sorted by id
9 */
10function mergeArrays(nums1: number[][], nums2: number[][]): number[][] {
11 // Maximum possible ID value (0-1000 range)
12 const MAX_ID: number = 1001;
13
14 // Initialize frequency/count array to store sum of values for each ID
15 const sumByID: number[] = new Array(MAX_ID).fill(0);
16
17 // Accumulate values from first array
18 for (const [id, value] of nums1) {
19 sumByID[id] += value;
20 }
21
22 // Accumulate values from second array
23 for (const [id, value] of nums2) {
24 sumByID[id] += value;
25 }
26
27 // Build result array with non-zero sums
28 const result: number[][] = [];
29 for (let id = 0; id < MAX_ID; ++id) {
30 // Only include IDs that have a positive sum
31 if (sumByID[id] > 0) {
32 result.push([id, sumByID[id]]);
33 }
34 }
35
36 return result;
37}
38
Time and Space Complexity
The time complexity is O((n + m) * log(n + m))
, where n
and m
are the lengths of nums1
and nums2
respectively. This is because:
- Concatenating the two arrays takes
O(n + m)
time - Iterating through all elements to update the Counter takes
O(n + m)
time - The
sorted()
function on the Counter items takesO(k * log(k))
time, wherek
is the number of unique IDs. In the worst case,k = n + m
(all IDs are unique)
The space complexity is O(n + m)
, which consists of:
- The concatenated list
nums1 + nums2
requiresO(n + m)
space - The Counter dictionary stores at most
n + m
unique key-value pairs in the worst case - The output list from
sorted(cnt.items())
also requiresO(k)
space wherek β€ n + m
Note: The reference answer suggests O(n + m)
time complexity, which would be achievable if the arrays were already sorted and merged using a two-pointer approach without the final sorting step. The reference's space complexity of O(M)
where M = 1000
assumes using a fixed-size array to count occurrences of IDs from 1 to 1000, rather than a dynamic Counter/dictionary.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Forgetting to handle the output format correctly
Pitfall: The sorted(cnt.items())
returns a list of tuples [(id1, value1), (id2, value2), ...]
, but the problem requires a list of lists [[id1, value1], [id2, value2], ...]
.
Why it happens: Python's dict.items()
naturally returns tuples, and it's easy to overlook that the problem specifically asks for nested lists.
Solution: Convert each tuple to a list explicitly:
return [list(item) for item in sorted(cnt.items())]
# OR
return [[i, v] for i, v in sorted(cnt.items())]
2. Attempting to use two-pointer approach without proper handling
Pitfall: While a two-pointer approach seems natural since both arrays are sorted, it requires careful handling of three cases: when ids match, when one id is smaller, and when one array is exhausted.
Example of buggy two-pointer code:
def mergeArrays(nums1, nums2):
result = []
i, j = 0, 0
while i < len(nums1) and j < len(nums2):
if nums1[i][0] == nums2[j][0]:
result.append([nums1[i][0], nums1[i][1] + nums2[j][1]])
i += 1
j += 1
# Missing logic for remaining elements!
return result
Solution: If using two pointers, ensure all cases are handled:
def mergeArrays(nums1, nums2):
result = []
i, j = 0, 0
while i < len(nums1) and j < len(nums2):
id1, val1 = nums1[i]
id2, val2 = nums2[j]
if id1 == id2:
result.append([id1, val1 + val2])
i += 1
j += 1
elif id1 < id2:
result.append([id1, val1])
i += 1
else:
result.append([id2, val2])
j += 1
# Don't forget remaining elements!
while i < len(nums1):
result.append(nums1[i])
i += 1
while j < len(nums2):
result.append(nums2[j])
j += 1
return result
3. Using regular dictionary instead of Counter
Pitfall: Using a regular dictionary and forgetting to initialize values:
cnt = {} for i, v in nums1 + nums2: cnt[i] += v # KeyError if i doesn't exist!
Solution: Either use Counter (which auto-initializes to 0) or handle initialization:
# Option 1: Use Counter (recommended)
cnt = Counter()
# Option 2: Use defaultdict
from collections import defaultdict
cnt = defaultdict(int)
# Option 3: Check existence manually
cnt = {}
for i, v in nums1 + nums2:
if i in cnt:
cnt[i] += v
else:
cnt[i] = v
# OR use get() method
# cnt[i] = cnt.get(i, 0) + v
Which of the following shows the order of node visit in a Breadth-first Search?
Recommended Readings
Tech Interview Pattern Two Pointers Introduction If you prefer videos here's a super quick introduction to Two Pointers div class responsive iframe iframe src https www youtube com embed xZ4AfXHQ1VQ title YouTube video player frameborder 0 allow accelerometer autoplay clipboard write encrypted media gyroscope picture in picture allowfullscreen iframe div Two pointers is a common interview
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Donβt Miss This!