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
idrepresents a unique identifier for a number - The
valuerepresents the value associated with thatid
Both input arrays are sorted in ascending order by id, and within each array, all ids are unique.
Your task is to merge these two arrays into a single array following these rules:
-
Include all unique ids: If an
idappears in eithernums1ornums2(or both), it should appear in the result. -
Sum the values: For each
idin the result:- If the
idexists in both arrays, its value should be the sum of values from both arrays - If the
idexists 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
idshould appear exactly once in the result.
For example, if nums1 = [[1,2], [3,4]] and nums2 = [[1,3], [2,5]]:
id1 appears in both arrays with values 2 and 3, so the result has[1, 5](2+3)id2 appears only innums2with value 5, so the result has[2, 5]id3 appears only innums1with 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
ids 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
idappears 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
Counterobject (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] += vFor each pair
[i, v]whereiis the id andvis the value:- If
ialready exists in the counter, we addvto its current sum - If
idoesn't exist, the Counter automatically initializes it to 0 and then addsv
- If
-
Convert to sorted result: After processing all pairs,
cntcontains each uniqueidas 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
idappears 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=2cnt[1] += 2- Counter becomes:
{1: 2}
-
Second pair
[3,4]:id=3, value=4cnt[3] += 4- Counter becomes:
{1: 2, 3: 4}
-
Third pair
[1,3]:id=1, value=3cnt[1] += 3(adds to existing value)- Counter becomes:
{1: 5, 3: 4}
-
Fourth pair
[2,5]:id=2, value=5cnt[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=1appeared in both arrays with values 2 and 3, summed to 5 ✓id=2appeared only innums2with value 5 ✓id=3appeared only innums1with 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
251class 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}
401class 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};
311/**
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}
38Time 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, wherekis 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 + nums2requiresO(n + m)space - The Counter dictionary stores at most
n + munique 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
Given a sorted array of integers and an integer called target, find the element that
equals to the target and return its index. Select the correct code that fills the
___ in the given code snippet.
1def binary_search(arr, target):
2 left, right = 0, len(arr) - 1
3 while left ___ right:
4 mid = (left + right) // 2
5 if arr[mid] == target:
6 return mid
7 if arr[mid] < target:
8 ___ = mid + 1
9 else:
10 ___ = mid - 1
11 return -1
121public static int binarySearch(int[] arr, int target) {
2 int left = 0;
3 int right = arr.length - 1;
4
5 while (left ___ right) {
6 int mid = left + (right - left) / 2;
7 if (arr[mid] == target) return mid;
8 if (arr[mid] < target) {
9 ___ = mid + 1;
10 } else {
11 ___ = mid - 1;
12 }
13 }
14 return -1;
15}
161function binarySearch(arr, target) {
2 let left = 0;
3 let right = arr.length - 1;
4
5 while (left ___ right) {
6 let mid = left + Math.trunc((right - left) / 2);
7 if (arr[mid] == target) return mid;
8 if (arr[mid] < target) {
9 ___ = mid + 1;
10 } else {
11 ___ = mid - 1;
12 }
13 }
14 return -1;
15}
16Recommended 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!