The nested list can contain integers or other nested lists at any depth. We can flatten the entire structure upfront using depth-first traversal. By storing all integers in a flat array during construction, subsequent next() and hasNext() calls become simple array operations.
0. Call dfs() on the nested list to populate the array.dfs() on that list.true if the pointer is less than the array length.class NestedIterator:
def __init__(self, nestedList):
self.arr = []
self.ptr = 0
self.dfs(nestedList)
def next(self):
val = self.arr[self.ptr]
self.ptr += 1
return val
def hasNext(self):
return self.ptr < len(self.arr)
def dfs(self, nestedArr):
for num in nestedArr:
if num.isInteger():
self.arr.append(num.getInteger())
else:
self.dfs(num.getList())Where is the number of integers and is the nesting depth.
This is a variation of the first approach where the recursive function returns a flattened list instead of modifying a global variable. Each recursive call builds and returns its own list, which gets merged into the parent's result.
dfs() on the nested list and store the returned array. Initialize pointer to 0.dfs() and extend the result with the returned list.true if the pointer is less than the array length.class NestedIterator:
def __init__(self, nestedList):
self.arr = self.dfs(nestedList)
self.ptr = 0
def dfs(self, nestedArr):
res = []
for num in nestedArr:
if num.isInteger():
res.append(num.getInteger())
else:
res.extend(self.dfs(num.getList()))
return res
def next(self):
val = self.arr[self.ptr]
self.ptr += 1
return val
def hasNext(self):
return self.ptr < len(self.arr)Where is the number of integers and is the nesting depth.
We can use recursion to flatten the list and store the integers in a stack. By reversing the stack after flattening, we can pop elements in the correct order. This combines recursive traversal with stack-based iteration.
dfs() on the nested list, then reverse the stack.dfs() on it.true if the stack is not empty.class NestedIterator:
def __init__(self, nestedList: [NestedInteger]):
self.stack = []
self.dfs(nestedList)
self.stack.reverse()
def next(self) -> int:
return self.stack.pop()
def hasNext(self) -> bool:
return len(self.stack) > 0
def dfs(self, nested):
for num in nested:
if num.isInteger():
self.stack.append(num.getInteger())
else:
self.dfs(num.getList())Where is the number of integers and is the nesting depth.
Instead of flattening everything upfront, we can flatten lazily using a stack. We push the NestedInteger objects themselves onto the stack (in reverse order). When checking hasNext(), we unpack nested lists on demand until we find an integer at the top. This approach is more memory-efficient when we don't need to iterate through all elements.
true.false if the stack becomes empty.class NestedIterator:
def __init__(self, nestedList: [NestedInteger]):
self.stack = nestedList
self.stack.reverse()
def next(self) -> int:
return self.stack.pop().getInteger()
def hasNext(self) -> bool:
while self.stack:
top = self.stack[-1]
if top.isInteger():
return True
self.stack.pop()
self.stack.extend(reversed(top.getList()))
return FalseWhere is the number of integers and is the nesting depth.
The iterator contract requires calling hasNext() before next(). In lazy evaluation approaches, hasNext() is responsible for ensuring an integer is at the top of the stack. Calling next() without first calling hasNext() may return a nested list object instead of an integer, or cause an exception when the stack is empty.
A nested list can contain empty lists like [[]] or [[], [1, []], 2]. Failing to handle these causes hasNext() to return true when no integers remain, or next() to fail. The lazy approach must continue unpacking until it finds an actual integer or the stack becomes empty.
When using a stack for lazy evaluation, elements must be pushed in reverse order so the first element ends up on top. Pushing in forward order reverses the iteration order. Similarly, when popping a nested list and pushing its contents, those contents must also be reversed to maintain correct order.