Problem

Given two values obj1 and obj2, return a deepmerged value.

Values should be deepmerged according to these rules:

  • If the two values are objects, the resulting object should have all the keys that exist on either object. If a key belongs to both objects, deepmerge the two associated values. Otherwise, add the key-value pair to the resulting object.
  • If the two values are arrays, the resulting array should be the same length as the longer array. Apply the same logic as you would with objects, but treat the indices as keys.
  • Otherwise the resulting value is obj2.

You can assume obj1 and obj2 are the output of JSON.parse().

Examples

Example 1:

1
2
3
Input: obj1 = {"a": 1, "c": 3}, obj2 = {"a": 2, "b": 2}
Output: {"a": 2, "c": 3, "b": 2}
Explanation: The value of obj1["a"] changed to 2 because if both objects have the same key and their value is not an array or object then we change the obj1 value to the obj2 value. Key "b" with value was added to obj1 as it doesn't exist in obj1. 

Example 2:

1
2
3
Input: obj1 = [{}, 2, 3], obj2 = [[], 5]
Output: [[], 5, 3]
Explanation: result[0] = obj2[0] because obj1[0] and obj2[0] have different types. result[2] = obj1[2] because obj2[2] does not exist.

Example 3:

1
2
3
4
5
6
7
Input: 
obj1 = {"a": 1, "b": {"c": [1 , [2, 7], 5], "d": 2}}, 
obj2 = {"a": 1, "b": {"c": [6, [6], [9]], "e": 3}}
Output: {"a": 1, "b": {"c": [6, [6, 7], [9]], "d": 2, "e": 3}}
Explanation: 
Arrays obj1["b"]["c"] and obj2["b"]["c"] have been merged in way that obj2 values overwrite obj1 values deeply only if they are not arrays or objects.
obj2["b"]["c"] has key "e" that obj1 doesn't have so it's added to obj1.

Example 4:

1
2
Input: obj1 = true, obj2 = null
Output: null

Constraints:

  • obj1 and obj2 are valid JSON values
  • 1 <= JSON.stringify(obj1).length <= 5 * 10^5
  • 1 <= JSON.stringify(obj2).length <= 5 * 10^5

Solution

Method 1 – Recursive Deep Merge

Intuition

To deeply merge two objects or arrays, we recursively merge their properties or elements. If both are objects, we merge by key; if both are arrays, we merge by index; otherwise, we return the second value. This ensures nested structures are merged according to the rules.

Approach

  1. If both values are arrays:
    • Create a new array of length equal to the longer array.
    • For each index, recursively merge the elements at that index from both arrays (if present).
  2. If both values are objects (but not arrays):
    • Create a new object with all keys from both objects.
    • For each key, recursively merge the values from both objects (if present).
  3. Otherwise, return the second value.
  4. Use recursion to handle nested structures.

Code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class Solution {
    deepMerge(obj1, obj2) {
        if (Array.isArray(obj1) && Array.isArray(obj2)) {
            const len = Math.max(obj1.length, obj2.length);
            const ans = [];
            for (let i = 0; i < len; i++) {
                if (i in obj1 && i in obj2) {
                    ans[i] = this.deepMerge(obj1[i], obj2[i]);
                } else if (i in obj1) {
                    ans[i] = obj1[i];
                } else {
                    ans[i] = obj2[i];
                }
            }
            return ans;
        }
        if (this.isObject(obj1) && this.isObject(obj2)) {
            const ans = {};
            const keys = new Set([...Object.keys(obj1), ...Object.keys(obj2)]);
            for (const k of keys) {
                if (k in obj1 && k in obj2) {
                    ans[k] = this.deepMerge(obj1[k], obj2[k]);
                } else if (k in obj1) {
                    ans[k] = obj1[k];
                } else {
                    ans[k] = obj2[k];
                }
            }
            return ans;
        }
        return obj2;
    }
    isObject(x) {
        return typeof x === 'object' && x !== null && !Array.isArray(x);
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class Solution {
    deepMerge(obj1: any, obj2: any): any {
        if (Array.isArray(obj1) && Array.isArray(obj2)) {
            const len = Math.max(obj1.length, obj2.length);
            const ans: any[] = [];
            for (let i = 0; i < len; i++) {
                if (i in obj1 && i in obj2) {
                    ans[i] = this.deepMerge(obj1[i], obj2[i]);
                } else if (i in obj1) {
                    ans[i] = obj1[i];
                } else {
                    ans[i] = obj2[i];
                }
            }
            return ans;
        }
        if (this.isObject(obj1) && this.isObject(obj2)) {
            const ans: Record<string, any> = {};
            const keys = new Set([...Object.keys(obj1), ...Object.keys(obj2)]);
            for (const k of keys) {
                if (k in obj1 && k in obj2) {
                    ans[k] = this.deepMerge(obj1[k], obj2[k]);
                } else if (k in obj1) {
                    ans[k] = obj1[k];
                } else {
                    ans[k] = obj2[k];
                }
            }
            return ans;
        }
        return obj2;
    }
    isObject(x: any): boolean {
        return typeof x === 'object' && x !== null && !Array.isArray(x);
    }
}

Complexity

  • ⏰ Time complexity: O(N), where N is the total number of keys and elements in all nested objects and arrays, since each value is visited once.
  • 🧺 Space complexity: O(D), where D is the maximum depth of the nested structure, due to recursion stack.