给你一个嵌套的整数列表 nestedList
。每个元素要么是一个整数,要么是一个列表;该列表的元素也可能是整数或者是其他列表。请你实现一个迭代器将其扁平化,使之能够遍历这个列表中的所有整数。
实现扁平迭代器类 NestedIterator
:
NestedIterator(List<NestedInteger> nestedList)
用嵌套列表 nestedList
初始化迭代器。
int next()
返回嵌套列表的下一个整数。
boolean hasNext()
如果仍然存在待迭代的整数,返回 true
;否则,返回 false
。
你的代码将会用下述伪代码检测:
initialize iterator with nestedList
res = []
while iterator.hasNext()
append iterator.next() to the end of res
return res
如果 res
与预期的扁平化列表匹配,那么你的代码将会被判为正确。
示例 1:
**输入:** nestedList = [[1,1],2,[1,1]]
**输出:** [1,1,2,1,1]
**解释:** 通过重复调用 _next_ 直到 _hasNex_ t 返回 false, _next _返回的元素的顺序应该是: [1,1,2,1,1]。
示例 2:
**输入:** nestedList = [1,[4,[6]]]
**输出:** [1,4,6]
**解释:** 通过重复调用 _next _直到 _hasNex_ t 返回 false, _next _返回的元素的顺序应该是: [1,4,6]。
提示:
1 <= nestedList.length <= 500
- 嵌套列表中的整数值在范围
[-106, 106]
内
方法一:深度优先搜索
思路
嵌套的整型列表是一个树形结构,树上的叶子节点对应一个整数,非叶节点对应一个列表。
在这棵树上深度优先搜索的顺序就是迭代器遍历的顺序。
我们可以先遍历整个嵌套列表,将所有整数存入一个数组,然后遍历该数组从而实现 next 和 hasNext 方法。
代码
[sol1-C++]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| class NestedIterator { private: vector<int> vals; vector<int>::iterator cur;
void dfs(const vector<NestedInteger> &nestedList) { for (auto &nest : nestedList) { if (nest.isInteger()) { vals.push_back(nest.getInteger()); } else { dfs(nest.getList()); } } }
public: NestedIterator(vector<NestedInteger> &nestedList) { dfs(nestedList); cur = vals.begin(); }
int next() { return *cur++; }
bool hasNext() { return cur != vals.end(); } };
|
[sol1-Java]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| public class NestedIterator implements Iterator<Integer> { private List<Integer> vals; private Iterator<Integer> cur;
public NestedIterator(List<NestedInteger> nestedList) { vals = new ArrayList<Integer>(); dfs(nestedList); cur = vals.iterator(); }
@Override public Integer next() { return cur.next(); }
@Override public boolean hasNext() { return cur.hasNext(); }
private void dfs(List<NestedInteger> nestedList) { for (NestedInteger nest : nestedList) { if (nest.isInteger()) { vals.add(nest.getInteger()); } else { dfs(nest.getList()); } } } }
|
[sol1-Golang]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| type NestedIterator struct { vals []int }
func Constructor(nestedList []*NestedInteger) *NestedIterator { var vals []int var dfs func([]*NestedInteger) dfs = func(nestedList []*NestedInteger) { for _, nest := range nestedList { if nest.IsInteger() { vals = append(vals, nest.GetInteger()) } else { dfs(nest.GetList()) } } } dfs(nestedList) return &NestedIterator{vals} }
func (it *NestedIterator) Next() int { val := it.vals[0] it.vals = it.vals[1:] return val }
func (it *NestedIterator) HasNext() bool { return len(it.vals) > 0 }
|
[sol1-JavaScript]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| var NestedIterator = function(nestedList) { vals = []; const dfs = (nestedList) => { for (const nest of nestedList) { if (nest.isInteger()) { vals.push(nest.getInteger()); } else { dfs(nest.getList()); } } } dfs(nestedList); };
NestedIterator.prototype.hasNext = function() { return vals.length > 0; };
NestedIterator.prototype.next = function() { const val = vals[0]; vals = vals.slice(1); return val; };
|
[sol1-C]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| struct NestedIterator { int *vals; int size; int cur; };
void dfs(struct NestedIterator *iter, struct NestedInteger **nestedList, int nestedListSize) { for (int i = 0; i < nestedListSize; i++) { if (NestedIntegerIsInteger(nestedList[i])) { (iter->vals)[(iter->size)++] = NestedIntegerGetInteger(nestedList[i]); } else { dfs(iter, NestedIntegerGetList(nestedList[i]), NestedIntegerGetListSize(nestedList[i])); } } }
struct NestedIterator *nestedIterCreate(struct NestedInteger **nestedList, int nestedListSize) { struct NestedIterator *ret = malloc(sizeof(struct NestedIterator)); ret->vals = malloc(sizeof(int) * 20001); ret->size = 0; ret->cur = 0; dfs(ret, nestedList, nestedListSize); return ret; }
bool nestedIterHasNext(struct NestedIterator *iter) { return iter->cur != iter->size; }
int nestedIterNext(struct NestedIterator *iter) { return (iter->vals)[(iter->cur)++]; }
void nestedIterFree(struct NestedIterator *iter) { free(iter->vals); free(iter); }
|
复杂度分析
方法二:栈
思路
我们可以用一个栈来代替方法一中的递归过程。
具体来说,用一个栈来维护深度优先搜索时,从根节点到当前节点路径上的所有节点。由于非叶节点对应的是一个列表,我们在栈中存储的是指向列表当前遍历的元素的指针(下标)。每次向下搜索时,取出列表的当前指针指向的元素并将其入栈,同时将该指针向后移动一位。如此反复直到找到一个整数。循环时若栈顶指针指向了列表末尾,则将其从栈顶弹出。
下面的代码中,C++ 和 Java 的栈存储的是迭代器,迭代器可以起到指向元素的指针的效果,Go 的栈存储的是切片(视作队列),通过将元素弹出队首的操作代替移动指针的操作。
代码
[sol2-C++]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| class NestedIterator { private: stack<pair<vector<NestedInteger>::iterator, vector<NestedInteger>::iterator>> stk;
public: NestedIterator(vector<NestedInteger> &nestedList) { stk.emplace(nestedList.begin(), nestedList.end()); }
int next() { return stk.top().first++->getInteger(); }
bool hasNext() { while (!stk.empty()) { auto &p = stk.top(); if (p.first == p.second) { stk.pop(); continue; } if (p.first->isInteger()) { return true; } auto &lst = p.first++->getList(); stk.emplace(lst.begin(), lst.end()); } return false; } };
|
[sol2-Java]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| public class NestedIterator implements Iterator<Integer> { private Deque<Iterator<NestedInteger>> stack;
public NestedIterator(List<NestedInteger> nestedList) { stack = new LinkedList<Iterator<NestedInteger>>(); stack.push(nestedList.iterator()); }
@Override public Integer next() { return stack.peek().next().getInteger(); }
@Override public boolean hasNext() { while (!stack.isEmpty()) { Iterator<NestedInteger> it = stack.peek(); if (!it.hasNext()) { stack.pop(); continue; } NestedInteger nest = it.next(); if (nest.isInteger()) { List<NestedInteger> list = new ArrayList<NestedInteger>(); list.add(nest); stack.push(list.iterator()); return true; } stack.push(nest.getList().iterator()); } return false; } }
|
[sol2-Golang]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| type NestedIterator struct { stack [][]*NestedInteger }
func Constructor(nestedList []*NestedInteger) *NestedIterator { return &NestedIterator{[][]*NestedInteger{nestedList}} }
func (it *NestedIterator) Next() int { queue := it.stack[len(it.stack)-1] val := queue[0].GetInteger() it.stack[len(it.stack)-1] = queue[1:] return val }
func (it *NestedIterator) HasNext() bool { for len(it.stack) > 0 { queue := it.stack[len(it.stack)-1] if len(queue) == 0 { it.stack = it.stack[:len(it.stack)-1] continue } nest := queue[0] if nest.IsInteger() { return true } it.stack[len(it.stack)-1] = queue[1:] it.stack = append(it.stack, nest.GetList()) } return false }
|
[sol2-JavaScript]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| var NestedIterator = function(nestedList) { this.stack = nestedList; };
NestedIterator.prototype.hasNext = function() { while (this.stack.length !== 0) { if (this.stack[0].isInteger()) { return true; } else { let cur = this.stack[0].getList(); this.stack.shift(); this.stack.unshift(...cur); } } };
NestedIterator.prototype.next = function() { return this.stack.shift().getInteger(); };
|
复杂度分析