嵌套列表迭代器-python

本题LeetCode链接:

https://leetcode-cn.com/problems/flatten-nested-list-iterator/

本题简单来说,就是对于一个多层嵌套的列表,按顺序输出里面的每一个内容,例如:

输入: [1,[4,[6]]]
输出: [1,4,6]

如果只是单纯地进行输出,那么可以很简单使用递归:

def fun(data):
    for i in data:
        if isinstance(i,int):
            print(i)
        else:
            fun(i)

data = [1,[4,[6]]]
fun(data)

针对列表的每一项,如果是整数,就直接输出,如果是列表,就递归。

评论区一位同学说得很好:

LeetCode上面的题目,对输出的要求进行了修改,要求以迭代器的形式输出,即:可以调用函数hasNext()判断是否有下一个元素,调用函数next()输出下一个元素。

那么本题有两个方法,第一种方法,就是在构造迭代器的时候,就使用上述递归方法,将每个元素都入队列,之后hasNext()判断队列是否为空即可,next()输出队列头即可。

带示例代码如下:

class KNode:
    def __init__(self,data) -> None:
        self.data = data

    def isInt(self) -> bool:
        """
        @return bool
        """
        return isinstance(self.data,int)
    def getInt(self) -> int:
        """
        @return the single Int that this KNode holds
        """
        return self.data
    def getList(self) :
        """
        @return the KNode list
        """
        return self.data

class KNodeIterator:
    def fun(self,data):
        for i in data:
            if i.isInt():
                self.queue.append(i)
            else:
                self.fun(i.getList())

    def __init__(self, KNodeList):
        """
        可以知道,这个地方的时间复杂度为O(N)
        """
        self.queue = []
        self.fun(KNodeList)

    def next(self) -> int:
        """
        要求O(1)
        """
        cur = self.queue.pop(0)
        return cur.getInt()

    def hasNext(self) -> bool:
        """
        时间复杂度O(1)
        """
        if self.queue:
            return True
        else:
            return False

a1 = KNode(1)
a2 = KNode(2)
a3 = KNode(3)
a4 = KNode(4)
a5 = KNode(5)

# kNodes = [5,[4],[3,[]],[2,1]]
kNodes = [KNode(5),KNode([KNode(4)]),KNode([KNode(3),KNode([])]),KNode([KNode(2),KNode(1)])]
iter = KNodeIterator(kNodes)

while iter.hasNext():
    # visit iter.next()
    print(iter.next())

但其实这个方法并不符合迭代器的思想,迭代器不应该在构造的时候,就将最终要输出的数据整理完毕,进行存储。也就是说,在构造函数中,时间复杂度应该为1,在hasNext的时候,再进行数据的整理。

在这里,我们将初始状态列表所有内容入栈,在hasNext的时候,判断栈顶是否为空,是否为整数,是否为列表。

如果是空,那么没有后续

如果是整数,那么有后续

如果是列表(列表可能为空),需要将列表中拆开,将里面的内容重新入栈。

即,对于样例:[1,[4,[6]]]

  1. 初始栈为:[1,[4,[6]]]    注:python的列表可以很方便进行最左侧操作,因此这里的栈的形式,和一般的栈的形式是反过来的。
  2. 将1出栈,栈为:[ [4,[6]] ]
  3. 将[4,[6]]拆解为4和[6],重新入栈,注意入栈顺序。入栈后,栈为:[4,[6]]
  4. 将4出栈,栈为:[[6]]
  5. 将[6]拆解为 6 ,重新入栈。入栈后,栈为:[6]
  6. 将6出栈,栈为:[ ]
  7. 栈空,无后续元素。

样例代码如下:

class KNode:
    def __init__(self,data) -> None:
        self.data = data

    def isInt(self) -> bool:
        """
        @return bool
        """
        return isinstance(self.data,int)
    def getInt(self) -> int:
        """
        @return the single Int that this KNode holds
        """
        return self.data
    def getList(self) :
        """
        @return the KNode list
        """
        return self.data

class KNodeIterator:

    def __init__(self, KNodeList):
        """
        时间复杂度为O(1)
        对于python来说,这个地方其实是一个列表的引用
        也就是说,后续对nodelist的操作,其实都是直接在kNodeList上的
        """
        self.nodelist = KNodeList

    def next(self) -> int:
        """
        要求O(1)
        """
        cur = self.nodelist.pop(0)
        return cur.getInt()

    def hasNext(self) -> bool:
        """
        一般时间复杂度O(1),最坏时间复杂度为O(N)
        """
        while self.nodelist:
            if self.nodelist[0].isInt():
                return True
            else:
                t = self.nodelist[0].getList()
                self.nodelist.pop(0)
                for i in range(len(t)-1,-1,-1):
                    self.nodelist.insert(0,t[i])
        return False
a1 = KNode(1)
a2 = KNode(2)
a3 = KNode(3)
a4 = KNode(4)
a5 = KNode(5)

# kNodes = [5,[4],[3,[]],[2,1]]
kNodes = [KNode(5),KNode([KNode(4)]),KNode([KNode(3),KNode([])]),KNode([KNode(2),KNode(1)])]
print(kNodes)
iter = KNodeIterator(kNodes)

while iter.hasNext():
    # visit iter.next()
    print(iter.next())
print(kNodes)

参考链接:

https://leetcode-cn.com/problems/flatten-nested-list-iterator/solution/fu-xue-ming-zhu-xiang-jie-ti-yi-shu-li-d-n4qa/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值