Facebook Pixel

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 that id

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:

  1. Include all unique ids: If an id appears in either nums1 or nums2 (or both), it should appear in the result.

  2. 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)
  3. Maintain sorted order: The resulting array must be sorted in ascending order by id.

  4. 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 in nums2 with value 5, so the result has [2, 5]
  • id 3 appears only in nums1 with value 4, so the result has [3, 4]
  • Final result: [[1,5], [2,5], [3,4]]
Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

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:

  1. What are all the unique ids across both arrays?
  2. 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:

  1. Initialize a Counter: We create a Counter object (which is a specialized dictionary in Python) to store the sum of values for each id.

    cnt = Counter()
  2. 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] where i is the id and v is the value:

    • If i already exists in the counter, we add v to its current sum
    • If i doesn't exist, the Counter automatically initializes it to 0 and then adds v
  3. Convert to sorted result: After processing all pairs, cnt contains each unique id 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 (the id) 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 Evaluator

Example 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 in nums2 with value 5 βœ“
  • id=3 appeared only in nums1 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 takes O(k * log(k)) time, where k 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 requires O(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 requires O(k) space where k ≀ 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
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

Which of the following shows the order of node visit in a Breadth-first Search?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More