第一章:题目不让我干什么,我偏要干什么

labuladong题目不让我干什么,我偏要干什么

341. 扁平化嵌套列表迭代器

示例 :
输入:nestedList = [1,[4,[6]]]
输出:[1,4,6]
解释:通过重复调用 next 直到 hasNext 返回 false,next 返回的元素的顺序应该是: [1,4,6]。

NestedInteger相当于一棵N叉树,叶子节点是int类型,其他节点是vector 类型。结果中保存叶子节点

  • 用递归实现展平
    • 如果是整数,则加到结果中
    • 如果是NestedInteger,则递归展开该NestedInteger,直到不能展开为止
    • 由于每次的for循环是有限的,因此不用显式地写递归出口,循环结束就是隐式的出口
  • 因为需要用next得到当前元素,并弹出当前元素,然后得到下一个元素,然后弹出下一个元素…,所以用队列存储结果
  • 也可以用向量存储结果。这时要记录当前位置的索引

各函数功能:

  • NestedIterator(vector <NestedInteger> &nestedList) 函数实现全部展开
  • int next() 队列中,函数得到当前元素,并弹出当前元素 (向量中,得到当前元素后,索引向后移动)
  • bool hasNext(): 队列中,通过NestedInteger的size()判断是否hasNext(),如果size>=1,则说明hasNext (向量中,索引值小于size(),则说明hasNext()

方法1:递归

第一种:队列实现

/**
 * // 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 {
private:
    queue<int> q;
public:
    void dfs(vector <NestedInteger> &nestedList) {
        for (NestedInteger &i:nestedList){
            if (i.isInteger()){
                q.push(i.getInteger());
            }
            else{
                dfs(i.getList());
            }
        }
    }

    NestedIterator(vector <NestedInteger> &nestedList) {
        dfs(nestedList);
    }

    int next() {
        int tmp=q.front();
        q.pop();
        return tmp;
    }

    bool hasNext() {
        return q.size();
    }
};

/**
 * Your NestedIterator object will be instantiated and called as such:
 * NestedIterator i(nestedList);
 * while (i.hasNext()) cout << i.next();
 */
# """
# 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 helper(self,nestedList):
        for i in nestedList:
            if i.isInteger():
                self.dq.append(i.getInteger())
            else:
                self.helper(i.getList())



    def __init__(self, nestedList):
        """
        Initialize your data structure here.
        :type nestedList: List[NestedInteger]
        """
        from collections import deque
        self.dq=deque()
        self.helper(nestedList)

    def next(self):
        """
        :rtype: int
        """
        return self.dq.popleft()

    def hasNext(self):
        """
        :rtype: bool
        """
        return len(self.dq)

# Your NestedIterator object will be instantiated and called as such:
# i, v = NestedIterator(nestedList), []
# while i.hasNext(): v.append(i.next())

第二种:向量实现

class NestedIterator {
private:
    vector<int> v;
    int idx = 0; // 加一个索引记录当前位置
public:
    void dfs(vector <NestedInteger> &nestedList) {
        for (NestedInteger &i:nestedList) {
            if (i.isInteger()) {
                v.push_back(i.getInteger());
            } else {
                dfs(i.getList());
            }
        }
    }

    NestedIterator(vector <NestedInteger> &nestedList) {
        dfs(nestedList);
    }

    int next() {
        // 也就是 return v[idx++];
        int tmp = v[idx];
        idx++;
        return tmp;
    }

    bool hasNext() {
//        return v.size(); // 这里不可以再用size()判断。
//        因为idx++,可能使idx越出v,导致内存溢出。ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6030000000c0

        return v.size() > idx;
    }
};

方法2:迭代

由于「栈」的先进后出的特性,我们需要逆序在栈里放入各个元素

处理流程分为两步:

在构造函数中应该初始化,把当前列表的各个元素(不用摊平)逆序放入栈中。
在 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;

    注意:while i.hasNext(): v.append(i.next())中,是while,所以当stack中是[3,2]时,会持续调用next()函数

  7. 再调用 hasNext() 方法时,栈为空,因此返回 false,迭代器运行结束。

使用stack实现:

class NestedIterator(object):

    def __init__(self, nestedList):
        """
        Initialize your data structure here.
        :type nestedList: List[NestedInteger]
        """
        self.stack = nestedList[::-1]# 逆序放入stack中

    def next(self):
        """
        :rtype: int
        """
        return self.stack.pop().getInteger()

    def hasNext(self):
        """
        :rtype: bool
        """
        while self.stack:
            top = self.stack[-1]
            if top.isInteger():# 如果是整数,则返回True
                return True
            self.stack = self.stack[:-1] + top.getList()[::-1] # 如果是nestList,则把stack顶的元素逆序,再反向拼接
        return 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

也可以用deque写

class NestedIterator(object):

    def __init__(self, nestedList):
        """
        Initialize your data structure here.
        :type nestedList: List[NestedInteger]
        """

        self.queue = collections.deque(nestedList)

    def next(self):
        """
        :rtype: int
        """
        return self.queue.popleft().getInteger()

    def hasNext(self):
        """
        :rtype: bool
        """
        while self.queue:
            if self.queue[0].isInteger():
                return True
            first = self.queue.popleft()
            self.queue.extendleft(first.getList()[::-1])
        return False

   转载规则


《第一章:题目不让我干什么,我偏要干什么》 M 采用 知识共享署名 4.0 国际许可协议 进行许可。
 上一篇
第三章:如何高效进行模幂运算 第三章:如何高效进行模幂运算
labuladong如何高效进行模幂运算 372. 超级次方先把问题分解为子问题 子问题1:如何高效求幂?对应以下题目: 50. Pow(x, n)快速幂解析(分治法角度) 通过x*x,每次x变为x^2; 通过n//2向下取整,n变为原来
2021-08-20
下一篇 
第四章:烧饼排序算法 第四章:烧饼排序算法
labuladong烧饼排序算法 969. 煎饼排序通过递归思想解决问题 (本题找到可行解即可,因此与示例的输出不一致,但仍能通过测试用例) 先把最大的烧饼放到最后面。怎么放呢? 找到最大烧饼对应的索引,翻转0到索引处的烧饼,先使最大烧饼
2021-08-19
  目录