339. Nested List Weight Sum π
Problem Description
You have a nested list structure where each element can be either:
- An integer
- A list containing more integers or nested lists
The depth of an integer is determined by how many levels of lists it's nested within. The outermost level has depth 1, elements inside one list have depth 2, elements inside two nested lists have depth 3, and so on.
For example, in the nested list [1,[2,2],[[3],2],1]
:
- The first
1
and last1
are at depth 1 (not inside any nested list) - The two
2
s in[2,2]
are at depth 2 (inside one list) - The
3
in[[3],2]
is at depth 3 (inside two nested lists) - The
2
in[[3],2]
is at depth 2 (inside one list)
Your task is to calculate the weighted sum where each integer is multiplied by its depth, then sum all these products together.
For the example above: 1*1 + 2*2 + 2*2 + 3*3 + 2*2 + 1*1 = 1 + 4 + 4 + 9 + 4 + 1 = 23
The solution uses a depth-first search (DFS) approach to traverse the nested structure. Starting with depth 1, it recursively processes each element:
- If an element is an integer, multiply it by the current depth and add to the sum
- If an element is a list, recursively process that list with depth increased by 1
The NestedInteger
interface provides methods to check if an element is an integer (isInteger()
), get the integer value (getInteger()
), or get the nested list (getList()
).
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 where each list is a node that can contain integers (leaf nodes) or other lists (child nodes). This forms a tree-like hierarchical structure.
Is it a tree?
- Yes: The nested list structure is actually a tree. Each list can contain multiple elements (children), but there are no cycles - each element belongs to exactly one parent list. The structure has a clear root (the outermost list) and branches down to leaf nodes (integers).
DFS
- Yes: Since we identified this as a tree structure, the flowchart leads us directly to DFS (Depth-First Search).
Conclusion: The flowchart suggests using DFS for this problem, which makes perfect sense because:
- We need to traverse each element in the nested structure
- We need to track the depth/level as we go deeper into nested lists
- DFS naturally maintains the depth information through its recursive call stack
- Each integer's contribution to the sum depends on how deep it is in the structure
The DFS approach allows us to:
- Start at depth 1 for the outermost level
- Recursively explore nested lists, incrementing the depth
- Calculate the weighted sum by multiplying each integer by its current depth
- Aggregate all the weighted values as we traverse the entire structure
Intuition
When we look at this nested list structure, we can think of it like a file system where folders can contain files or other folders. Just as we might calculate the total size of files weighted by how deep they are in the directory structure, here we need to calculate a weighted sum based on nesting depth.
The key insight is recognizing that this is fundamentally a tree traversal problem. Each list is like a node that can have children (either integers or other lists). The "depth" mentioned in the problem is essentially the level of the node in this tree.
Why DFS? Consider how we naturally think about processing nested structures - we would:
- Look at each element in the current list
- If it's a number, we know its depth (current level) and can calculate its contribution
- If it's another list, we need to "dive into" that list first before moving to the next element
This "dive deep first" approach is exactly what DFS does. The beautiful part about using recursion for DFS here is that the call stack naturally keeps track of our current depth. Each recursive call represents going one level deeper, so we can simply pass depth + 1
to the recursive call.
Think about manually calculating the sum for [1,[2,2],[[3],2],1]
:
- Start at depth 1: see
1
(contribute1*1
) - Still at depth 1: see
[2,2]
- need to go deeper- Now at depth 2: see
2
(contribute2*2
), see another2
(contribute2*2
)
- Now at depth 2: see
- Back to depth 1: see
[[3],2]
- need to go deeper- Now at depth 2: see
[3]
- need to go even deeper- Now at depth 3: see
3
(contribute3*3
)
- Now at depth 3: see
- Back to depth 2: see
2
(contribute2*2
)
- Now at depth 2: see
- Back to depth 1: see
1
(contribute1*1
)
This natural way of thinking through the problem maps perfectly to a recursive DFS solution where each function call handles one level of nesting and returns the sum of all integers at that level and below.
Solution Approach
The implementation uses a recursive DFS helper function to traverse the nested list structure. Let's walk through the solution step by step:
Main Function Setup:
def depthSum(self, nestedList: List[NestedInteger]) -> int:
return dfs(nestedList, 1)
We start by calling our helper function with the initial list and depth of 1.
DFS Helper Function:
def dfs(nestedList, depth):
depth_sum = 0
for item in nestedList:
if item.isInteger():
depth_sum += item.getInteger() * depth
else:
depth_sum += dfs(item.getList(), depth + 1)
return depth_sum
The algorithm works as follows:
-
Initialize a local sum: For each recursive call, we maintain
depth_sum
to accumulate the weighted values at this level and all deeper levels. -
Iterate through each element: We process each
NestedInteger
object in the current list. -
Check element type: Using the
isInteger()
method from the NestedInteger interface:- If it's an integer: We get its value using
getInteger()
, multiply by the currentdepth
, and add to our sum - If it's a nested list: We recursively call
dfs()
with:- The nested list obtained via
getList()
- Incremented depth (
depth + 1
) - Add the returned sum to our current
depth_sum
- The nested list obtained via
- If it's an integer: We get its value using
-
Return the accumulated sum: After processing all elements at this level, return the total sum.
Key Design Decisions:
-
Recursion over iteration: While we could use an iterative approach with a stack, recursion naturally handles the depth tracking through the call stack.
-
Passing depth as parameter: Instead of maintaining a global depth variable, we pass depth as a parameter, making the function pure and easier to reason about.
-
Single pass traversal: Each element is visited exactly once, making the solution efficient with
O(n)
time complexity wheren
is the total number of integers in the structure.
Example Walkthrough with [1,[2,2],[[3],2],1]
:
dfs([1,[2,2],[[3],2],1], 1)
starts- Processes
1
: adds1*1 = 1
- Processes
[2,2]
: callsdfs([2,2], 2)
- Adds
2*2 = 4
and2*2 = 4
, returns 8
- Adds
- Processes
[[3],2]
: callsdfs([[3],2], 2)
- Processes
[3]
: callsdfs([3], 3)
- Adds
3*3 = 9
, returns 9
- Adds
- Processes
2
: adds2*2 = 4
- Returns 13
- Processes
- Processes
1
: adds1*1 = 1
- Returns total:
1 + 8 + 13 + 1 = 23
- Processes
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 simpler example: [[1,1],2,[1,1]]
Visual representation of the structure:
[ [1, 1], // depth 1: this is a list 2, // depth 1: integer value 2 [1, 1] // depth 1: this is a list ]
Step-by-step execution:
-
Start:
dfs([[1,1],2,[1,1]], depth=1)
- Initialize
depth_sum = 0
- Begin iterating through the list
- Initialize
-
First element
[1,1]
:- It's not an integer (it's a list)
- Make recursive call:
dfs([1,1], depth=2)
- In this recursive call with depth=2:
- First
1
: is integer β add1 * 2 = 2
- Second
1
: is integer β add1 * 2 = 2
- Return
4
back to parent call
- First
- In this recursive call with depth=2:
- Add returned value:
depth_sum = 0 + 4 = 4
-
Second element
2
:- It's an integer
- Calculate:
2 * 1 = 2
(depth is 1) - Add to sum:
depth_sum = 4 + 2 = 6
-
Third element
[1,1]
:- It's not an integer (it's a list)
- Make recursive call:
dfs([1,1], depth=2)
- In this recursive call with depth=2:
- First
1
: is integer β add1 * 2 = 2
- Second
1
: is integer β add1 * 2 = 2
- Return
4
back to parent call
- First
- In this recursive call with depth=2:
- Add returned value:
depth_sum = 6 + 4 = 10
-
Final result: Return
10
Calculation breakdown:
- Two
1
s from first[1,1]
at depth 2:1*2 + 1*2 = 4
- One
2
at depth 1:2*1 = 2
- Two
1
s from second[1,1]
at depth 2:1*2 + 1*2 = 4
- Total: 4 + 2 + 4 = 10
This example demonstrates how the recursive DFS naturally handles the depth tracking - each time we encounter a nested list, we increment the depth by 1 in the recursive call, and when we return from that call, we're automatically back at the previous depth level.
Solution Implementation
1# """
2# This is the interface that allows for creating nested lists.
3# You should not implement it, or speculate about its implementation
4# """
5# class NestedInteger:
6# def __init__(self, value=None):
7# """
8# If value is not specified, initializes an empty list.
9# Otherwise initializes a single integer equal to value.
10# """
11#
12# def isInteger(self):
13# """
14# @return True if this NestedInteger holds a single integer, rather than a nested list.
15# :rtype bool
16# """
17#
18# def add(self, elem):
19# """
20# Set this NestedInteger to hold a nested list and adds a nested integer elem to it.
21# :rtype void
22# """
23#
24# def setInteger(self, value):
25# """
26# Set this NestedInteger to hold a single integer equal to value.
27# :rtype void
28# """
29#
30# def getInteger(self):
31# """
32# @return the single integer that this NestedInteger holds, if it holds a single integer
33# Return None if this NestedInteger holds a nested list
34# :rtype int
35# """
36#
37# def getList(self):
38# """
39# @return the nested list that this NestedInteger holds, if it holds a nested list
40# Return None if this NestedInteger holds a single integer
41# :rtype List[NestedInteger]
42# """
43
44from typing import List
45
46
47class Solution:
48 def depthSum(self, nestedList: List[NestedInteger]) -> int:
49 """
50 Calculate the sum of all integers in the nested list weighted by their depth.
51 Each integer is multiplied by its depth (starting from 1).
52
53 Args:
54 nestedList: A list of NestedInteger objects
55
56 Returns:
57 The weighted sum of all integers
58 """
59
60 def calculate_depth_sum(nested_list: List[NestedInteger], depth: int) -> int:
61 """
62 Recursively calculate the weighted sum for a given depth level.
63
64 Args:
65 nested_list: List of NestedInteger objects at current level
66 depth: Current depth level (starting from 1)
67
68 Returns:
69 Sum of all integers weighted by their depth
70 """
71 total_sum = 0
72
73 # Iterate through each element in the current level
74 for element in nested_list:
75 if element.isInteger():
76 # If it's an integer, add its value multiplied by current depth
77 total_sum += element.getInteger() * depth
78 else:
79 # If it's a nested list, recursively process it with increased depth
80 total_sum += calculate_depth_sum(element.getList(), depth + 1)
81
82 return total_sum
83
84 # Start the recursive calculation from depth 1
85 return calculate_depth_sum(nestedList, 1)
86
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 /**
31 * Calculates the weighted sum of all integers in the nested list structure.
32 * Each integer is multiplied by its depth level (starting from 1).
33 *
34 * @param nestedList The input list containing NestedInteger elements
35 * @return The total weighted sum of all integers
36 */
37 public int depthSum(List<NestedInteger> nestedList) {
38 // Start DFS traversal with initial depth of 1
39 return calculateDepthSum(nestedList, 1);
40 }
41
42 /**
43 * Recursively calculates the weighted sum using depth-first search.
44 *
45 * @param nestedList The current list of NestedInteger elements to process
46 * @param currentDepth The current depth level in the nested structure
47 * @return The weighted sum for this level and all nested levels
48 */
49 private int calculateDepthSum(List<NestedInteger> nestedList, int currentDepth) {
50 int totalSum = 0;
51
52 // Iterate through each element in the current list
53 for (NestedInteger element : nestedList) {
54 if (element.isInteger()) {
55 // If element is an integer, add its weighted value to the sum
56 totalSum += element.getInteger() * currentDepth;
57 } else {
58 // If element is a nested list, recursively calculate its sum with increased depth
59 totalSum += calculateDepthSum(element.getList(), currentDepth + 1);
60 }
61 }
62
63 return totalSum;
64 }
65}
66
1/**
2 * Interface for creating nested lists.
3 * Each element is either an integer or a list whose elements may also be integers or other lists.
4 */
5class NestedInteger {
6public:
7 /**
8 * Returns true if this NestedInteger holds a single integer, rather than a nested list.
9 */
10 bool isInteger() const;
11
12 /**
13 * Returns the single integer that this NestedInteger holds, if it holds a single integer.
14 * Returns 0 if this NestedInteger holds a nested list.
15 */
16 int getInteger() const;
17
18 /**
19 * Sets this NestedInteger to hold a single integer equal to value.
20 */
21 void setInteger(int value);
22
23 /**
24 * Sets this NestedInteger to hold a nested list and adds a nested integer elem to it.
25 */
26 void add(const NestedInteger &elem);
27
28 /**
29 * Returns the nested list that this NestedInteger holds, if it holds a nested list.
30 * Returns empty vector if this NestedInteger holds a single integer.
31 */
32 const vector<NestedInteger> &getList() const;
33};
34
35class Solution {
36public:
37 /**
38 * Calculates the sum of all integers in the nested list weighted by their depth.
39 * Each integer is multiplied by its depth (starting from 1).
40 *
41 * @param nestedList - Vector of NestedInteger objects to process
42 * @return The weighted sum of all integers by their depth
43 */
44 int depthSum(vector<NestedInteger>& nestedList) {
45 // Start the recursive calculation with depth 1
46 return calculateDepthSum(nestedList, 1);
47 }
48
49private:
50 /**
51 * Recursive helper function to traverse the nested structure.
52 *
53 * @param currentList - Current list being processed
54 * @param currentDepth - Current depth level (starting from 1)
55 * @return Sum of integers at this level and below, weighted by depth
56 */
57 int calculateDepthSum(const vector<NestedInteger>& currentList, int currentDepth) {
58 int totalSum = 0;
59
60 // Iterate through each element in the current list
61 for (const auto& element : currentList) {
62 if (element.isInteger()) {
63 // If element is an integer, add its weighted value to the sum
64 totalSum += element.getInteger() * currentDepth;
65 } else {
66 // If element is a list, recursively process it with increased depth
67 totalSum += calculateDepthSum(element.getList(), currentDepth + 1);
68 }
69 }
70
71 return totalSum;
72 }
73};
74
1/**
2 * Interface for creating nested lists.
3 * Each element is either an integer or a list whose elements may also be integers or other lists.
4 */
5interface NestedInteger {
6 /**
7 * Returns true if this NestedInteger holds a single integer, rather than a nested list.
8 */
9 isInteger(): boolean;
10
11 /**
12 * Returns the single integer that this NestedInteger holds, if it holds a single integer.
13 * Returns null if this NestedInteger holds a nested list.
14 */
15 getInteger(): number | null;
16
17 /**
18 * Sets this NestedInteger to hold a single integer equal to value.
19 */
20 setInteger(value: number): void;
21
22 /**
23 * Sets this NestedInteger to hold a nested list and adds a nested integer elem to it.
24 */
25 add(elem: NestedInteger): void;
26
27 /**
28 * Returns the nested list that this NestedInteger holds, if it holds a nested list.
29 * Returns null if this NestedInteger holds a single integer.
30 */
31 getList(): NestedInteger[] | null;
32}
33
34/**
35 * Calculates the sum of all integers in the nested list weighted by their depth.
36 * Each integer is multiplied by its depth (starting from 1).
37 *
38 * @param nestedList - Array of NestedInteger objects to process
39 * @returns The weighted sum of all integers by their depth
40 */
41function depthSum(nestedList: NestedInteger[]): number {
42 /**
43 * Recursive helper function to traverse the nested structure.
44 *
45 * @param currentList - Current list being processed
46 * @param currentDepth - Current depth level (starting from 1)
47 * @returns Sum of integers at this level and below, weighted by depth
48 */
49 const calculateDepthSum = (currentList: NestedInteger[], currentDepth: number): number => {
50 let totalSum: number = 0;
51
52 // Iterate through each element in the current list
53 for (const element of currentList) {
54 if (element.isInteger()) {
55 // If element is an integer, add its weighted value to the sum
56 totalSum += element.getInteger()! * currentDepth;
57 } else {
58 // If element is a list, recursively process it with increased depth
59 totalSum += calculateDepthSum(element.getList()!, currentDepth + 1);
60 }
61 }
62
63 return totalSum;
64 };
65
66 // Start the recursive calculation with depth 1
67 return calculateDepthSum(nestedList, 1);
68}
69
Time and Space Complexity
Time Complexity: O(n)
where n
is the total number of elements (including nested elements) in the entire nested list structure.
The algorithm uses depth-first search (DFS) to traverse through all elements in the nested list. Each element is visited exactly once:
- For integers: We perform a constant time operation (
getInteger()
and multiplication) - For nested lists: We make a recursive call to process its contents
Since every element (whether it's an integer or a nested list) is processed exactly once, the time complexity is linear with respect to the total number of elements.
Space Complexity: O(d)
where d
is the maximum depth of nesting in the input.
The space complexity is determined by:
- The recursive call stack: In the worst case, the recursion depth equals the maximum nesting level of the input structure
- Local variables in each recursive call: Only a constant amount of space (
depth_sum
,item
,depth
) is used per recursive call
For example, for a deeply nested structure like [[[[1]]]]
, the recursion would go 4 levels deep, using O(4)
space on the call stack. The space complexity does not depend on the total number of elements but rather on how deeply they are nested.
Common Pitfalls
1. Incorrect Depth Initialization
One of the most common mistakes is starting the depth at 0 instead of 1. The problem clearly states that the outermost level has depth 1, not depth 0.
Incorrect Implementation:
def depthSum(self, nestedList: List[NestedInteger]) -> int:
return calculate_depth_sum(nestedList, 0) # Wrong! Starting at depth 0
Why it's wrong: This would calculate 1*0 + 2*1 + 2*1 + 3*2 + 2*1 + 1*0 = 0 + 2 + 2 + 6 + 2 + 0 = 12
instead of the correct answer 23.
Solution: Always start with depth 1 as shown in the correct implementation.
2. Mishandling the NestedInteger Interface
Another pitfall is incorrectly using the NestedInteger methods or making assumptions about the data structure.
Common Mistakes:
# Mistake 1: Trying to iterate directly over a NestedInteger for item in element: # Wrong! NestedInteger is not iterable ... # Mistake 2: Forgetting to call getList() for nested lists if not element.isInteger(): total_sum += calculate_depth_sum(element, depth + 1) # Wrong! Should be element.getList() # Mistake 3: Assuming getInteger() works on lists value = element.getInteger() # This returns None if element is a list!
Solution: Always check isInteger()
first, then use the appropriate method:
- Use
getInteger()
only whenisInteger()
returns True - Use
getList()
only whenisInteger()
returns False
3. Incrementing Depth Incorrectly
Some implementations mistakenly modify the depth variable instead of passing depth + 1
.
Incorrect Implementation:
def calculate_depth_sum(nested_list, depth):
total_sum = 0
for element in nested_list:
if element.isInteger():
total_sum += element.getInteger() * depth
else:
depth += 1 # Wrong! This affects subsequent elements at the same level
total_sum += calculate_depth_sum(element.getList(), depth)
return total_sum
Why it's wrong: If you have [1, [2], 3]
, after processing [2]
, the depth would be permanently increased, causing 3
to be calculated with the wrong depth.
Solution: Always pass depth + 1
as a parameter without modifying the current depth variable:
total_sum += calculate_depth_sum(element.getList(), depth + 1)
4. Edge Case: Empty Lists
Not handling empty nested lists properly can lead to issues in some implementations.
Potential Issue:
# Some might try to optimize by checking list length first
if len(element.getList()) > 0: # Unnecessary and could cause issues
total_sum += calculate_depth_sum(element.getList(), depth + 1)
Solution: The recursive function naturally handles empty lists by returning 0 (the loop simply doesn't execute), so no special handling is needed. The implementation should work correctly with inputs like [[],[[]],1]
.
5. Type Confusion with Mixed Implementations
When solving this problem outside of LeetCode's environment, developers might mix different representations.
Common Mistake:
# Mixing Python lists with NestedInteger objects
def calculate_depth_sum(nested_list, depth):
total_sum = 0
for element in nested_list:
if isinstance(element, int): # Wrong! Should use isInteger()
total_sum += element * depth
elif isinstance(element, list): # Wrong! Should use getList()
total_sum += calculate_depth_sum(element, depth + 1)
return total_sum
Solution: Consistently use the NestedInteger interface methods (isInteger()
, getInteger()
, getList()
) rather than Python's built-in type checking.
How does merge sort divide the problem into subproblems?
Recommended Readings
https assets algo monster cover_photos dfs svg Depth First Search Prereqs Recursion Review problems recursion_intro Trees problems tree_intro With a solid understanding of recursion under our belts we are now ready to tackle one of the most useful techniques in coding interviews Depth First Search DFS As the name suggests
https assets algo monster cover_photos bfs svg Breadth First Search on Trees Hopefully by this time you've drunk enough DFS Kool Aid to understand its immense power and seen enough visualization to create a call stack in your mind Now let me introduce the companion spell Breadth First Search BFS
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
Want a Structured Path to Master System Design Too? Donβt Miss This!