341. Flatten Nested List Iterator
- Total Accepted: 20339
- Total Submissions: 55207
- Difficulty: Medium
- Contributors: Admin
Given a nested list of integers, implement an iterator to flatten it.
Each element is either an integer, or a list — whose elements may also be integers or other lists.
Example 1:
Given the list [[1,1],2,[1,1]]
,
By calling next repeatedly until hasNext returns false, the order of elements returned by next should be: [1,1,2,1,1]
.
Example 2:
Given the list [1,[4,[6]]]
,
By calling next repeatedly until hasNext returns false, the order of elements returned by next should be: [1,4,6]
.
Code
# """ # This is the interface that allows for creating nested lists. # You should not implement it, or speculate about its implementation # """ #class NestedInteger(object): # def isInteger(self): # """ # @return True if this NestedInteger holds a single integer, rather than a nested list. # :rtype bool # """ # # def getInteger(self): # """ # @return the single integer that this NestedInteger holds, if it holds a single integer # Return None if this NestedInteger holds a nested list # :rtype int # """ # # def getList(self): # """ # @return the nested list that this NestedInteger holds, if it holds a nested list # Return None if this NestedInteger holds a single integer # :rtype List[NestedInteger] # """ class NestedIterator(object): def __init__(self, nestedList): """ Initialize your data structure here. :type nestedList: List[NestedInteger] """ # initialize a pair. 1st: the next element to explore, # 2nd: the next index of that element to explore, if that element is a list-like NestedInteger self.stack = [[nestedList, 0]] def next(self): """ :rtype: int """ # hasNext() always makes sure the latest element on self.stack # is a list containing a non-list NestedInteger if self.hasNext(): l, idx = self.stack.pop() return l.getInteger() def hasNext(self): """ # hasNext() always makes sure the latest element on self.stack # is a list containing a non-list NestedInteger :rtype: bool """ while self.stack: l, idx = self.stack[-1] if type(l) is NestedInteger and l.isInteger(): return True else: if type(l) is NestedInteger and idx < len(l.getList()): self.stack[-1][1] += 1 self.stack.append([l.getList()[idx], 0]) # the first added element in self.__init__ is a pure list elif type(l) is list and idx < len(l): self.stack[-1][1] += 1 self.stack.append([l[idx], 0]) else: # pop the element if the idx, the next position to explore, has already # exceeded the length of the element self.stack.pop() return False # Your NestedIterator object will be instantiated and called as such: # i, v = NestedIterator(nestedList), [] # while i.hasNext(): v.append(i.next())
Idea
Use a stack to maintain the elements to iterate. The next element to be iterated will be on the top of the stack. The stack is initialized as [nestedList, 0]
in self.__init__()
, as we are going to explore the first element in nestedList
in the future.
In self.next()
, we always first call self.hasNext()
. The goal of self.hasNext()
is to put the next integer on the top of the stack and also a boolean indicating whether there indeed exists the next integer to iterate.
In self.hasNext()
, we peek the top element in the stack (line 55). If it is already an integer, return True and we don’t need to arrange the stack further. If it is a list of integers, we need to start exploring that list and put the next integer on the stack. Before that, we need to increase the top element’s index by one (line 60 and 64). This means that the next time when we visit this list, we should start exploring from the updated index.
The advantage of this algorithm is that it does not need to load all integers of the whole list into the stack at one time. Its space complexity is O(K), where K is the depth of the deepest nested list.
Reference: https://discuss.leetcode.com/topic/41870/real-iterator-in-python-java-c