2021-8-16 341. Flattened nested list iterator (dfs, stack)

Posted by camadan on Thu, 23 Dec 2021 04:55:33 +0100

Note:

Title:
Give you a nested list of integers nestedList. Each element is either an integer or a list; The elements of the list may also be integers or other lists. Please implement an iterator to flatten it so that it can traverse all integers in this list.

Implement the flat iterator class nesteditor:

Nesteditor (list nestedList) initializes the iterator with a nested list nestedList.
int next() returns the next integer of the nested list.
boolean hasNext() returns true if there are still integers to be iterated; Otherwise, false is returned.
Your code will be detected with the following pseudocode:

initialize iterator with nestedList
res = []
while iterator.hasNext()
    append iterator.next() to the end of res
return res

If res matches the expected flattened list, your code will be judged correct.

Example 1:
Input: nestedList = [[1,1],2,[1,1]]
Output: [1,1,2,1,1]
Explanation: call next repeatedly until hasNext returns false. The order of elements returned by next should be: [1,1,2,1,1].
Example 2:
Input: nestedList = [1,[4,[6]]]
Output: [1,4,6]
Explanation: call next repeatedly until hasNext returns false. The order of elements returned by next should be: [1,4,6].

Tips:
1 <= nestedList.length <= 500
The integer value in the nested list is in the range [- 106, 106]

Solution:
Method 1 dfs
thinking
The nested integer list is a tree structure. The leaf node on the tree corresponds to an integer and the non leaf node corresponds to a list.

The order of depth first search in this tree is the order of iterator traversal.

We can first traverse the entire nested list, store all integers in an array, and then traverse the array to implement the next and hasNext methods.

Complexity analysis
Time complexity: initialize to O(n), next and hasNext to O(1). Where nn is the number of elements in the nested integer list.

Space complexity: O(n). You need an array to store all the elements in a nested integer list.

/**
 * // This is the interface that allows for creating nested lists.
 * // You should not implement it, or speculate about its implementation
 * class NestedInteger {
 *   public:
 *     // Return true if this NestedInteger holds a single integer, rather than a nested list.
 *     bool isInteger() const;
 *
 *     // Return the single integer that this NestedInteger holds, if it holds a single integer
 *     // The result is undefined if this NestedInteger holds a nested list
 *     int getInteger() const;
 *
 *     // Return the nested list that this NestedInteger holds, if it holds a nested list
 *     // The result is undefined if this NestedInteger holds a single integer
 *     const vector<NestedInteger> &getList() const;
 * };
 */

class NestedIterator {
public:
    vector<int> result;
    vector<int>::iterator cur;
    void dfs(vector<NestedInteger> lists){
        for(auto list:lists){
            if(list.isInteger()){
                result.push_back(list.getInteger());
            }
            else{
                dfs(list.getList());
            }
        }
    } 
    NestedIterator(vector<NestedInteger> &nestedList) {
        dfs(nestedList);
        cur=result.begin();
    }
    
    int next() {
        return *(cur++);
    }
    
    bool hasNext() {
        return cur!=result.end();
    }
};

/**
 * Your NestedIterator object will be instantiated and called as such:
 * NestedIterator i(nestedList);
 * while (i.hasNext()) cout << i.next();
 */

Method 2 stack
thinking
We can replace the recursive process in method 1 with a stack.

Specifically, when a stack is used to maintain the depth first search, all nodes on the path from the root node to the current node. Since the non leaf node corresponds to a list, What we store in the stack is a pointer (subscript) to the element currently traversed by the list. Each time we search down, we take out the element pointed by the current pointer of the list and put it into the stack, and move the pointer back one bit. This is repeated until an integer is found. If the pointer at the top of the stack points to the end of the list during the loop, it will pop up from the top of the stack.

Complexity analysis
Time complexity: initialization and next are O(1), hasNext is equal sharing O(1).

Space complexity: O(n). In the worst case, the nested integer list is a chain. We need an O(n) stack to store all the elements on the chain.

/**
 * // This is the interface that allows for creating nested lists.
 * // You should not implement it, or speculate about its implementation
 * class NestedInteger {
 *   public:
 *     // Return true if this NestedInteger holds a single integer, rather than a nested list.
 *     bool isInteger() const;
 *
 *     // Return the single integer that this NestedInteger holds, if it holds a single integer
 *     // The result is undefined if this NestedInteger holds a nested list
 *     int getInteger() const;
 *
 *     // Return the nested list that this NestedInteger holds, if it holds a nested list
 *     // The result is undefined if this NestedInteger holds a single integer
 *     const vector<NestedInteger> &getList() const;
 * };
 */

class NestedIterator {
public:

    stack<pair<vector<NestedInteger>::iterator,vector<NestedInteger>::iterator>> stk;
    NestedIterator(vector<NestedInteger> &nestedList) {
        stk.emplace(nestedList.begin(),nestedList.end());
    }
    
    int next() {
        return stk.top().first++->getInteger();
    }
    
    bool hasNext() {
        while(!stk.empty()){
            pair<vector<NestedInteger>::iterator,vector<NestedInteger>::iterator> &p=stk.top();
            if(p.first==p.second){
                stk.pop();
                continue;
            }
             // Returns true if the current element is an integer
            if(p.first->isInteger()==true){
                return true;
            }
            // If the current element is a list, it is stacked and the iterator p points to the next element
            vector<NestedInteger> &t=p.first++->getList();
            stk.emplace(t.begin(),t.end());
        }
        return false;
    }
};

/**
 * Your NestedIterator object will be instantiated and called as such:
 * NestedIterator i(nestedList);
 * while (i.hasNext()) cout << i.next();
 */