原文链接: https://leetcode-cn.com/problems/flatten-nested-list-iterator
英文原文
You are given a nested list of integers nestedList
. Each element is either an integer or a list whose elements may also be integers or other lists. Implement an iterator to flatten it.
Implement the NestedIterator
class:
NestedIterator(List<NestedInteger> nestedList)
Initializes the iterator with the nested listnestedList
.int next()
Returns the next integer in the nested list.boolean hasNext()
Returnstrue
if there are still some integers in the nested list andfalse
otherwise.
Your code will be tested 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, then your code will be judged as correct.
Example 1:
Input: nestedList = [[1,1],2,[1,1]] Output: [1,1,2,1,1] Explanation: By calling 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: By calling next repeatedly until hasNext returns false, the order of elements returned by next should be: [1,4,6].
Constraints:
1 <= nestedList.length <= 500
- The values of the integers in the nested list is in the range
[-106, 106]
.
中文题目
给你一个嵌套的整数列表 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 直到 hasNext 返回 false,next 返回的元素的顺序应该是: [1,1,2,1,1]
。
示例 2:
输入:nestedList = [1,[4,[6]]]
输出:[1,4,6]
解释:通过重复调用 next 直到 hasNext 返回 false,next 返回的元素的顺序应该是: [1,4,6]
。
提示:
1 <= nestedList.length <= 500
- 嵌套列表中的整数值在范围
[-106, 106]
内
通过代码
高赞题解
各位题友大家好! 今天是 @负雪明烛 坚持日更的第 58 天。今天力扣上的每日一题是「341. 扁平化嵌套列表迭代器」。
题意解析
今天的题意略难理解,需要我翻译一下,理解题意的朋友请跳过。
本题定义了一个类 NestedInteger
,这个类可以存储 int
或 List<NestedInteger>
;所以称它是一个「嵌套列表」。类似于一棵多叉树,每个节点都可以有很多子节点。
它有三个方法:
isInteger()
,判断当前存储的对象是否为 int;getInteger()
, 如果当前存储的元素是 int 型的,那么返回当前的结果 int,否则调用会失败;getList()
,如果当前存储的元素是List<NestedInteger>
型的,那么返回该 List,否则调用会失败。
而「扁平化嵌套列表迭代器」说的是,我们需要设计一个迭代器,这个迭代器是把「嵌套列表」铺平(拆包)成各个 int,然后每次调用 hasNext()
来判断是否有下一个整数,通过 next()
返回下一个整数。
注意迭代器是一种按照特定顺序对数据结构遍历的方式,它的调用方式是:
i, v = NestedIterator(nestedList), []
while i.hasNext():
v.append(i.next())
解题思路
本文有两种主要的思路:
- 在构造函数中提前「扁平化」整个嵌套列表;
- 在调用
hasNext()
或者next()
方法的时候扁平化当前的嵌套的子列表。
一、递归:构造函数中提前「扁平化」整个嵌套列表
这是最简单的方法,但是我认为这不是面试官想要的方法。
在构造函数中提前扁平化整个嵌套列表。那么在 hasNext()
或者 next()
可以很简单地返回迭代器位置的 int。
因为这个嵌套的数据结构有点类似于多叉树,所以我们可以按照类似地遍历思路:递归。
承载遍历结果的数据结构可以使用数组,那么另外需要一个整数标记当前的迭代器指向的位置;也可以使用一个队列,每次调用 next()
方法的时候从队列的开头弹出一个元素。
递归的思路比较简单,我用的是队列:
- 遍历输入的「嵌套列表」所有的元素,判断每个元素是 int 还是 list;
- 如果当前元素是 int,放入队列尾部;
- 如果当前元素是 list,那么需要对当前 子list 继续递归;
其余代码比较简单,不作赘述。
class NestedIterator(object):
def dfs(self, nests):
for nest in nests:
if nest.isInteger():
self.queue.append(nest.getInteger())
else:
self.dfs(nest.getList())
def __init__(self, nestedList):
self.queue = collections.deque()
self.dfs(nestedList)
def next(self):
return self.queue.popleft()
def hasNext(self):
return len(self.queue)
- 时间复杂度:构造函数的时间复杂度是 $O(N)$;
next()
和hasNext()
的时间复杂度是 $O(1)$。 - 空间复杂度:$O(N)$。
二、迭代:调用 hasNext()
或者 next()
方法的时候扁平化当前的嵌套的子列表
这个方法更加有挑战性,也是这个题最正确的解法。因为对于大部分情况,我们希望迭代器能够一边迭代一边获取当前的结果,而不是提前初始化好。
把递归方法 转 迭代方法,我们需要用到「栈」。
在递归方法中,我们在遍历时如果遇到一个嵌套的 子list,就立即处理该 子list,直到全部展开;
在迭代方法中,我们不需要全部展开,只需要把 当前list 的所有元素放入 list 中。
由于「栈」的先进后出的特性,我们需要逆序在栈里放入各个元素。
处理流程分为两步:
- 在构造函数中应该初始化,把当前列表的各个元素(不用摊平)逆序放入栈中。
- 在
hasNext()
方法中,访问(不弹出)栈顶元素,判断是否为 int:
- 如果是 int 那么说明有下一个元素,返回 true;然后
next()
就会被调用,把栈顶的 int 弹出; - 如果是 list 需要把当前列表的各个元素(不用摊平)逆序放入栈中。
- 如果栈为空,那么说明原始的嵌套列表已经访问结束了,返回 false。
算法整体的流程,通过举例说明。假如输入 [1, [2,3]]
。
1. 在构造函数中:栈里面放的应该是 stack = [[2, 3], 1]
2. 在调用 hasNext() 方法时,访问栈顶元素是 1,为 int,那么直接返回 true;
3. 然后调用 next() 方法,弹出栈顶元素 1;
4. 再调用 hasNext() 方法时,访问栈顶元素是 [2,3],为 list,那么需要摊平,继续放到栈中。
当前的栈是 stack = [3, 2]
5. 然后调用 next() 方法,弹出栈顶元素 2;
6. 然后调用 next() 方法,弹出栈顶元素 3;
7. 再调用 hasNext() 方法时,栈为空,因此返回 false,迭代器运行结束。
这里需要说一下为什么在 hasNext()
方法中摊平 list,而不是在 next()
方法中。比如对于 [[]]
的输入, hasNext()
方法是判断其中是否有 int 元素了,则必须把内层的 list 摊平来看,发现是空的,返回 false。
代码如下:
class NestedIterator(object):
def __init__(self, nestedList):
self.stack = []
for i in range(len(nestedList) - 1, -1, -1):
self.stack.append(nestedList[i])
def next(self):
cur = self.stack.pop()
return cur.getInteger()
def hasNext(self):
while self.stack:
cur = self.stack[-1]
if cur.isInteger():
return True
self.stack.pop()
for i in range(len(cur.getList()) - 1, -1, -1):
self.stack.append(cur.getList()[i])
return False
class NestedIterator {
public:
NestedIterator(vector<NestedInteger> &nestedList) {
for (int i = nestedList.size() - 1; i >= 0; --i) {
st.push(nestedList[i]);
}
}
int next() {
NestedInteger cur = st.top(); st.pop();
return cur.getInteger();
}
bool hasNext() {
while (!st.empty()) {
NestedInteger cur = st.top();
if (cur.isInteger()) {
return true;
}
st.pop();
for (int i = cur.getList().size() - 1; i >= 0; --i) {
st.push(cur.getList()[i]);
}
}
return false;
}
private:
stack<NestedInteger> st;
};
- 时间复杂度:构造函数的最坏时间复杂度是 $O(N)$;
next()
和hasNext()
的最坏时间复杂度是 $O(N)$。 - 空间复杂度:$O(N)$。
刷题心得
面试的时候需要写出方法二,今天的题目很好,请务必掌握呀。
参考资料:
力扣官方题解
341. Flatten Nested List Iterator
OK,以上就是 @负雪明烛 写的今天题解的全部内容了,如果你觉得有帮助的话,求赞、求关注、求收藏。如果有疑问的话,请在下面评论,我会及时解答。
关注我,你将不会错过我的精彩动画题解、面试题分享、组队刷题活动,进入主页 @负雪明烛 右侧有刷题组织,从此刷题不再孤单。
祝大家牛年大吉!AC 多多,Offer 多多!我们明天再见!
统计信息
通过次数 | 提交次数 | AC比率 |
---|---|---|
53229 | 73216 | 72.7% |
提交历史
提交时间 | 提交结果 | 执行时间 | 内存消耗 | 语言 |
---|
相似题目
题目 | 难度 |
---|---|
展开二维向量 | 中等 |
锯齿迭代器 | 中等 |
迷你语法分析器 | 中等 |
数组嵌套 | 中等 |