Facebook Pixel

364. Nested List Weight Sum II 🔒

Problem Description

You are given a nested list of integers where each element can be either:

  • An integer
  • A list containing integers or other lists (which can be nested further)

The depth of an integer is determined by how many lists it is nested inside. For example, in the nested list [1,[2,2],[[3],2],1]:

  • The first 1 and last 1 are at depth 1 (inside one list)
  • The two 2s in [2,2] are at depth 2 (inside two lists)
  • The 3 in [[3],2] is at depth 3 (inside three lists)
  • The 2 in [[3],2] is at depth 2 (inside two lists)

The weight of an integer is calculated using the formula: weight = maxDepth - depth + 1, where maxDepth is the maximum depth of any integer in the entire nested list.

Your task is to calculate the sum of all integers in the nested list, where each integer is multiplied by its weight.

For example, if maxDepth = 3 for the list [1,[2,2],[[3],2],1]:

  • The integers at depth 1 have weight = 3 - 1 + 1 = 3
  • The integers at depth 2 have weight = 3 - 2 + 1 = 2
  • The integers at depth 3 have weight = 3 - 3 + 1 = 1

The final result would be: 1×3 + 2×2 + 2×2 + 3×1 + 2×2 + 1×3 = 3 + 4 + 4 + 3 + 4 + 3 = 21

Flowchart Walkthrough

First, let's pin down the algorithm using the Flowchart. Here's a step-by-step walkthrough:

Is it a graph?

  • Yes: The nested list structure can be viewed as a graph/tree where each list is a node that can contain integers (leaf nodes) or other lists (child nodes). This hierarchical structure represents a tree-like graph.

Is it a tree?

  • Yes: The nested list structure is indeed a tree. Each nested list represents a node in the tree, with integers as leaf nodes and sublists as internal nodes. There's a clear parent-child relationship without cycles, making it a tree structure.

DFS

  • Yes: We arrive at DFS as our algorithm choice.

Conclusion: The flowchart suggests using a Depth-First Search (DFS) approach for this problem.

This makes perfect sense because:

  1. We need to traverse through all levels of nesting to find the maximum depth
  2. We need to visit every integer in the nested structure while tracking its depth
  3. DFS naturally handles the recursive nature of nested lists, allowing us to dive deep into each nested level before backtracking
  4. The depth tracking during DFS traversal directly corresponds to counting how many lists each integer is nested within

The DFS approach allows us to:

  • Calculate the depth of each integer as we traverse
  • Keep track of the maximum depth encountered
  • Accumulate the sum of integers and their weighted sums in a single pass
  • Handle the recursive structure of nested lists naturally
Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

The key insight is recognizing that calculating weights directly would require two passes through the nested list: first to find the maximum depth, then to calculate the weighted sum. But we can be clever about this.

Let's think about what we're actually computing. For each integer with value v at depth d, its contribution to the final sum is v × (maxDepth - d + 1). If we expand this:

  • v × (maxDepth - d + 1)
  • v × maxDepth - v × d + v

If we sum this across all integers, we get:

  • (sum of all v × maxDepth) - (sum of all v × d) + (sum of all v)
  • maxDepth × (sum of all v) - (sum of all v × d) + (sum of all v)
  • (maxDepth + 1) × (sum of all v) - (sum of all v × d)

This transformation is brilliant because it separates our calculation into two parts:

  1. s: The simple sum of all integers
  2. ws: The weighted sum where each integer is multiplied by its depth

During a single DFS traversal, we can:

  • Track the current depth as we descend into nested lists
  • Update the maximum depth whenever we encounter an integer
  • Add each integer to our simple sum s
  • Add each integer multiplied by its current depth to our weighted sum ws

After the traversal, we have everything we need: maxDepth, s, and ws. The final answer is simply (maxDepth + 1) × s - ws.

This approach transforms what seems like a two-pass problem (find max depth, then calculate weighted sum) into an elegant single-pass solution using mathematical manipulation.

Solution Approach

The implementation uses DFS with three tracking variables: maxDepth, s (simple sum), and ws (weighted sum by depth).

DFS Function Design:

We create a helper function dfs(x, d) that processes a NestedInteger object x at depth d:

  1. Update Maximum Depth: First, we update maxDepth = max(maxDepth, d) to track the deepest level we've encountered.

  2. Handle Base Case (Integer): If x.isInteger() returns True:

    • Add the integer value to our simple sum: s += x.getInteger()
    • Add the depth-weighted value to our weighted sum: ws += x.getInteger() * d
  3. Handle Recursive Case (List): If x is a list:

    • Iterate through each element y in x.getList()
    • Recursively call dfs(y, d + 1) to process each element at the next depth level

Main Algorithm:

  1. Initialize our tracking variables: maxDepth = s = ws = 0

  2. Process the input nestedList:

    • For each top-level element x in nestedList
    • Call dfs(x, 1) starting at depth 1
  3. Calculate the final result using our mathematical formula:

    • Return (maxDepth + 1) * s - ws

Why This Works:

The algorithm leverages the mathematical transformation we derived:

  • Instead of calculating weight = maxDepth - depth + 1 for each integer after finding maxDepth
  • We collect s (sum of all integers) and ws (sum of integers × their depths) in one pass
  • Then apply the formula (maxDepth + 1) × s - ws to get the same result

Time and Space Complexity:

  • Time: O(n) where n is the total number of elements (integers and lists) in the nested structure
  • Space: O(d) where d is the maximum depth, for the recursion call stack

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 the solution with the nested list [[1,1],2,[1,1]].

Step 1: Visualize the Structure

[[1,1],2,[1,1]]
├── [1,1]      (depth 1)
│   ├── 1      (depth 2)
│   └── 1      (depth 2)
├── 2          (depth 1)
└── [1,1]      (depth 1)
    ├── 1      (depth 2)
    └── 1      (depth 2)

Step 2: DFS Traversal

Initialize: maxDepth = 0, s = 0, ws = 0

Process first element [1,1] at depth 1:

  • It's a list, so recurse into its elements
  • Process first 1 at depth 2:
    • Update: maxDepth = 2
    • Add to simple sum: s = 0 + 1 = 1
    • Add to weighted sum: ws = 0 + (1 × 2) = 2
  • Process second 1 at depth 2:
    • maxDepth remains 2
    • Update: s = 1 + 1 = 2
    • Update: ws = 2 + (1 × 2) = 4

Process second element 2 at depth 1:

  • It's an integer
  • maxDepth remains 2
  • Update: s = 2 + 2 = 4
  • Update: ws = 4 + (2 × 1) = 6

Process third element [1,1] at depth 1:

  • It's a list, so recurse into its elements
  • Process first 1 at depth 2:
    • maxDepth remains 2
    • Update: s = 4 + 1 = 5
    • Update: ws = 6 + (1 × 2) = 8
  • Process second 1 at depth 2:
    • maxDepth remains 2
    • Update: s = 5 + 1 = 6
    • Update: ws = 8 + (1 × 2) = 10

Step 3: Apply the Formula

After traversal, we have:

  • maxDepth = 2
  • s = 6 (sum of all integers: 1+1+2+1+1)
  • ws = 10 (weighted sum by depth: 1×2 + 1×2 + 2×1 + 1×2 + 1×2)

Final result: (maxDepth + 1) × s - ws = (2 + 1) × 6 - 10 = 18 - 10 = 8

Step 4: Verify with Direct Calculation

Let's verify by calculating weights directly:

  • Integers at depth 1 have weight = 2 - 1 + 1 = 2
  • Integers at depth 2 have weight = 2 - 2 + 1 = 1

Weighted sum:

  • Four integers (1,1,1,1) at depth 2: 4 × 1 = 4
  • One integer (2) at depth 1: 2 × 2 = 4
  • Total: 4 + 4 = 8 ✓

The formula correctly transforms the two-pass weight calculation into a single-pass algorithm by collecting the simple sum and depth-weighted sum during traversal.

Solution Implementation

1class Solution:
2    def depthSumInverse(self, nestedList: List[NestedInteger]) -> int:
3        """
4        Calculate the inverse depth sum of a nested list.
5        Each integer is multiplied by its inverse depth weight.
6      
7        Args:
8            nestedList: A list of NestedInteger objects
9          
10        Returns:
11            The sum where each integer is weighted by (max_depth - current_depth + 1)
12        """
13      
14        def traverse_nested_list(nested_integer, current_depth):
15            """
16            Recursively traverse the nested structure to calculate sums and find max depth.
17          
18            Args:
19                nested_integer: Current NestedInteger object to process
20                current_depth: Current depth level (starting from 1)
21            """
22            nonlocal max_depth, total_sum, weighted_sum_by_depth
23          
24            # Update the maximum depth encountered
25            max_depth = max(max_depth, current_depth)
26          
27            if nested_integer.isInteger():
28                # If it's a single integer, add it to our sums
29                integer_value = nested_integer.getInteger()
30                total_sum += integer_value  # Sum of all integers
31                weighted_sum_by_depth += integer_value * current_depth  # Sum weighted by depth
32            else:
33                # If it's a list, recursively process each element at the next depth level
34                for nested_element in nested_integer.getList():
35                    traverse_nested_list(nested_element, current_depth + 1)
36      
37        # Initialize tracking variables
38        max_depth = 0  # Maximum depth found in the nested structure
39        total_sum = 0  # Sum of all integers regardless of depth
40        weighted_sum_by_depth = 0  # Sum of integers weighted by their depth
41      
42        # Process each top-level element in the nested list
43        for nested_element in nestedList:
44            traverse_nested_list(nested_element, 1)
45      
46        # Calculate inverse depth sum using the formula:
47        # For each integer v at depth d: contribution = v * (max_depth - d + 1)
48        # Total = Σ(v * (max_depth - d + 1)) = (max_depth + 1) * Σv - Σ(v * d)
49        return (max_depth + 1) * total_sum - weighted_sum_by_depth
50
1/**
2 * // This is the interface that allows for creating nested lists.
3 * // You should not implement it, or speculate about its implementation
4 * public interface NestedInteger {
5 *     // Constructor initializes an empty nested list.
6 *     public NestedInteger();
7 *
8 *     // Constructor initializes a single integer.
9 *     public NestedInteger(int value);
10 *
11 *     // @return true if this NestedInteger holds a single integer, rather than a nested list.
12 *     public boolean isInteger();
13 *
14 *     // @return the single integer that this NestedInteger holds, if it holds a single integer
15 *     // Return null if this NestedInteger holds a nested list
16 *     public Integer getInteger();
17 *
18 *     // Set this NestedInteger to hold a single integer.
19 *     public void setInteger(int value);
20 *
21 *     // Set this NestedInteger to hold a nested list and adds a nested integer to it.
22 *     public void add(NestedInteger ni);
23 *
24 *     // @return the nested list that this NestedInteger holds, if it holds a nested list
25 *     // Return empty list if this NestedInteger holds a single integer
26 *     public List<NestedInteger> getList();
27 * }
28 */
29class Solution {
30    // Maximum depth encountered during traversal
31    private int maxDepth;
32  
33    // Weighted sum: sum of (value * depth) for all integers
34    private int weightedSum;
35  
36    // Simple sum: sum of all integer values (without weights)
37    private int simpleSum;
38
39    /**
40     * Calculates the inverse depth sum of nested integers.
41     * Each integer is multiplied by its inverse depth weight.
42     * The inverse depth weight is (maxDepth - currentDepth + 1).
43     * 
44     * Formula used: (maxDepth + 1) * simpleSum - weightedSum
45     * This formula efficiently computes the inverse depth sum without a second pass.
46     * 
47     * @param nestedList List of nested integers to process
48     * @return The inverse depth sum of all integers in the nested structure
49     */
50    public int depthSumInverse(List<NestedInteger> nestedList) {
51        // Process each element in the input list starting at depth 1
52        for (NestedInteger nestedInteger : nestedList) {
53            dfs(nestedInteger, 1);
54        }
55      
56        // Calculate inverse depth sum using the mathematical transformation
57        // This avoids needing a second traversal to apply inverse weights
58        return (maxDepth + 1) * simpleSum - weightedSum;
59    }
60
61    /**
62     * Depth-first search to traverse the nested structure.
63     * Accumulates both weighted and simple sums while tracking maximum depth.
64     * 
65     * @param nestedInteger Current nested integer being processed
66     * @param currentDepth Current depth in the nested structure (1-indexed)
67     */
68    private void dfs(NestedInteger nestedInteger, int currentDepth) {
69        // Update the maximum depth encountered
70        maxDepth = Math.max(maxDepth, currentDepth);
71      
72        if (nestedInteger.isInteger()) {
73            // Process integer value: add to both weighted and simple sums
74            int value = nestedInteger.getInteger();
75            weightedSum += value * currentDepth;
76            simpleSum += value;
77        } else {
78            // Process nested list: recursively traverse each element
79            for (NestedInteger childNestedInteger : nestedInteger.getList()) {
80                dfs(childNestedInteger, currentDepth + 1);
81            }
82        }
83    }
84}
85
1/**
2 * // This is the interface that allows for creating nested lists.
3 * // You should not implement it, or speculate about its implementation
4 * class NestedInteger {
5 *   public:
6 *     // Constructor initializes an empty nested list.
7 *     NestedInteger();
8 *
9 *     // Constructor initializes a single integer.
10 *     NestedInteger(int value);
11 *
12 *     // Return true if this NestedInteger holds a single integer, rather than a nested list.
13 *     bool isInteger() const;
14 *
15 *     // Return the single integer that this NestedInteger holds, if it holds a single integer
16 *     // The result is undefined if this NestedInteger holds a nested list
17 *     int getInteger() const;
18 *
19 *     // Set this NestedInteger to hold a single integer.
20 *     void setInteger(int value);
21 *
22 *     // Set this NestedInteger to hold a nested list and adds a nested integer to it.
23 *     void add(const NestedInteger &ni);
24 *
25 *     // Return the nested list that this NestedInteger holds, if it holds a nested list
26 *     // The result is undefined if this NestedInteger holds a single integer
27 *     const vector<NestedInteger> &getList() const;
28 * };
29 */
30class Solution {
31public:
32    /**
33     * Calculate the inverse depth sum of nested integers
34     * Each integer is multiplied by its inverse depth (maxDepth - depth + 1)
35     * 
36     * @param nestedList: List of nested integers to process
37     * @return: The inverse depth weighted sum of all integers
38     */
39    int depthSumInverse(vector<NestedInteger>& nestedList) {
40        int maxDepth = 0;           // Maximum depth found in the nested structure
41        int weightedSum = 0;         // Sum of each integer multiplied by its depth
42        int totalSum = 0;            // Sum of all integers (unweighted)
43      
44        // DFS function to traverse the nested structure
45        // Parameters: current NestedInteger element and its depth
46        function<void(NestedInteger&, int)> dfs = [&](NestedInteger& element, int depth) {
47            // Update maximum depth encountered
48            maxDepth = max(maxDepth, depth);
49          
50            if (element.isInteger()) {
51                // If element is an integer, add to both sums
52                int value = element.getInteger();
53                weightedSum += value * depth;      // Add value weighted by current depth
54                totalSum += value;                  // Add unweighted value
55            } else {
56                // If element is a list, recursively process each item
57                for (auto& nestedElement : element.getList()) {
58                    dfs(nestedElement, depth + 1);
59                }
60            }
61        };
62      
63        // Process each element in the input list starting at depth 1
64        for (auto& element : nestedList) {
65            dfs(element, 1);
66        }
67      
68        // Calculate inverse depth sum using the formula:
69        // inverseDepthSum = (maxDepth + 1) * totalSum - weightedSum
70        // This formula converts depth weights to inverse depth weights
71        return (maxDepth + 1) * totalSum - weightedSum;
72    }
73};
74
1/**
2 * // This is the interface that allows for creating nested lists.
3 * // You should not implement it, or speculate about its implementation
4 * class NestedInteger {
5 *     If value is provided, then it holds a single integer
6 *     Otherwise it holds an empty nested list
7 *     constructor(value?: number) {
8 *         ...
9 *     };
10 *
11 *     Return true if this NestedInteger holds a single integer, rather than a nested list.
12 *     isInteger(): boolean {
13 *         ...
14 *     };
15 *
16 *     Return the single integer that this NestedInteger holds, if it holds a single integer
17 *     Return null if this NestedInteger holds a nested list
18 *     getInteger(): number | null {
19 *         ...
20 *     };
21 *
22 *     Set this NestedInteger to hold a single integer equal to value.
23 *     setInteger(value: number) {
24 *         ...
25 *     };
26 *
27 *     Set this NestedInteger to hold a nested list and adds a nested integer elem to it.
28 *     add(elem: NestedInteger) {
29 *         ...
30 *     };
31 *
32 *     Return the nested list that this NestedInteger holds,
33 *     or an empty list if this NestedInteger holds a single integer
34 *     getList(): NestedInteger[] {
35 *         ...
36 *     };
37 * };
38 */
39
40/**
41 * Calculates the inverse depth sum of a nested list structure.
42 * Each integer is multiplied by its inverse depth (maxDepth - currentDepth + 1).
43 * 
44 * The algorithm uses a mathematical transformation:
45 * Instead of calculating (maxDepth - depth + 1) * value for each integer,
46 * it computes (maxDepth + 1) * sum - weightedSum
47 * where weightedSum is the sum of each integer multiplied by its actual depth.
48 * 
49 * @param nestedList - Array of NestedInteger objects to process
50 * @returns The inverse depth sum of all integers in the nested structure
51 */
52function depthSumInverse(nestedList: NestedInteger[]): number {
53    // Track maximum depth found in the structure
54    let maxDepth: number = 0;
55  
56    // Sum of all integers multiplied by their respective depths
57    let weightedSum: number = 0;
58  
59    // Simple sum of all integers (without depth weighting)
60    let totalSum: number = 0;
61  
62    /**
63     * Depth-first search to traverse the nested structure.
64     * Accumulates weighted sum and total sum while tracking maximum depth.
65     * 
66     * @param nestedInteger - Current NestedInteger being processed
67     * @param currentDepth - Current depth level (1-indexed)
68     */
69    const traverseNested = (nestedInteger: NestedInteger, currentDepth: number): void => {
70        // Update the maximum depth encountered
71        maxDepth = Math.max(maxDepth, currentDepth);
72      
73        if (nestedInteger.isInteger()) {
74            // Process integer value: add to weighted sum and total sum
75            const integerValue: number = nestedInteger.getInteger()!;
76            weightedSum += integerValue * currentDepth;
77            totalSum += integerValue;
78        } else {
79            // Process nested list: recursively traverse each element
80            const nestedElements: NestedInteger[] = nestedInteger.getList();
81            for (const element of nestedElements) {
82                traverseNested(element, currentDepth + 1);
83            }
84        }
85    };
86  
87    // Process each element in the input list starting at depth 1
88    for (const element of nestedList) {
89        traverseNested(element, 1);
90    }
91  
92    // Apply the mathematical transformation to get inverse depth sum
93    // This is equivalent to: sum of (maxDepth - depth + 1) * value for each integer
94    return (maxDepth + 1) * totalSum - weightedSum;
95}
96

Time and Space Complexity

Time Complexity: O(n)

The algorithm performs a depth-first search (DFS) traversal through all elements in the nested list structure. Each integer in the nested structure is visited exactly once during the traversal. For each integer encountered, the algorithm performs constant-time operations:

  • Updating maxDepth with a max comparison
  • Adding the integer value to the sum s
  • Adding the weighted value to ws

Since we visit each of the n integers exactly once and perform O(1) operations for each, the overall time complexity is O(n), where n is the total number of integers in the nested structure.

Space Complexity: O(d)

The space complexity is determined by the recursive call stack of the DFS function. The maximum depth of recursion equals the maximum nesting depth d of the input structure. Each recursive call adds a new frame to the call stack, consuming O(1) space for the function parameters and local variables. Therefore, the worst-case space complexity is O(d), where d is the maximum depth of nesting.

Note: The reference answer states O(n) for space complexity, which would be accurate if considering the worst-case scenario where the nested structure forms a linear chain (like [[[[[5]]]]]), making the depth equal to n. In general practice, the space complexity is more precisely described as O(d) where d is the maximum nesting depth.

Common Pitfalls

1. Incorrect Initial Depth Value

One of the most common mistakes is starting the traversal with depth 0 instead of depth 1. The problem states that elements in the outermost list are at depth 1, not depth 0.

Incorrect Implementation:

# Wrong: Starting with depth 0
for nested_element in nestedList:
    traverse_nested_list(nested_element, 0)  # ❌ Should be 1

Correct Implementation:

# Correct: Starting with depth 1
for nested_element in nestedList:
    traverse_nested_list(nested_element, 1)  # ✓

2. Misunderstanding the NestedInteger Interface

Developers often confuse how to handle the NestedInteger interface, particularly when dealing with empty lists or assuming the wrong return types.

Common Mistakes:

# Wrong: Assuming getList() returns integers directly
for element in nested_integer.getList():
    total_sum += element  # ❌ element is NestedInteger, not int

# Wrong: Not checking if it's an integer before calling getInteger()
value = nested_integer.getInteger()  # ❌ May fail if it's a list

Correct Approach:

if nested_integer.isInteger():
    value = nested_integer.getInteger()
    # Process integer value
else:
    for nested_element in nested_integer.getList():
        # Process each NestedInteger recursively

3. Formula Application Error

The mathematical formula (maxDepth + 1) * s - ws might be incorrectly implemented, especially with off-by-one errors.

Incorrect Implementations:

# Wrong formulas that developers might use:
return maxDepth * total_sum - weighted_sum_by_depth  # ❌ Missing +1
return (maxDepth - 1) * total_sum + weighted_sum_by_depth  # ❌ Wrong signs
return total_sum * maxDepth - weighted_sum_by_depth + total_sum  # ❌ Expanded incorrectly

Correct Formula:

return (max_depth + 1) * total_sum - weighted_sum_by_depth  # ✓

4. Variable Scope Issues with Nested Functions

Forgetting to use nonlocal for variables that need to be modified within the nested function.

Incorrect Implementation:

def depthSumInverse(self, nestedList):
    max_depth = 0
    total_sum = 0
    weighted_sum_by_depth = 0
  
    def traverse_nested_list(nested_integer, current_depth):
        # ❌ Without nonlocal, these create new local variables
        max_depth = max(max_depth, current_depth)  # UnboundLocalError
        total_sum += value  # UnboundLocalError

Correct Implementation:

def traverse_nested_list(nested_integer, current_depth):
    nonlocal max_depth, total_sum, weighted_sum_by_depth  # ✓
    max_depth = max(max_depth, current_depth)
    # ... rest of the function

5. Handling Edge Cases

Not properly handling edge cases like empty lists or deeply nested empty structures.

Potential Issues:

  • Empty input list [] should return 0
  • Nested empty lists like [[[]]] should not affect the result
  • Single integer wrapped in multiple lists [[[5]]] should be handled correctly

Robust Solution:

# Handle empty input
if not nestedList:
    return 0

# The existing algorithm naturally handles empty nested lists
# since they don't contain integers to add to the sums
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

Which of the two traversal algorithms (BFS and DFS) can be used to find whether two nodes are connected?


Recommended Readings

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

Load More