• 扁平化嵌套列表迭代器 [树的递归前序遍历 + 迭代前序遍历]


    前言

    问题转换:将需求确认,结合已学知识,进行匹配->改进。列表的扁平化本质就是树的前序遍历,不过不需要父节点而已。树的前序遍历可以递归实现,也可以迭代实现,一题多解,方便理解树的递归结构,前序遍历的多递归本质!才能对里面的知识点融汇贯通,举一反三!

    一、扁平化嵌套列表迭代器

    在这里插入图片描述

    二、前序遍历(无需访问非叶节点)

    1、递归实现

    // 扁平化嵌套列表迭代器。
    public class NestedIterator implements Iterator<Integer> {
        List<Integer> arr = new ArrayList<>();
        int idx = 0;
    
        // 层层嵌套,就像是学过的树结构,integer为叶子节点,list为父节点。
        // 扁平化的过程就像是前序遍历一样。
        public NestedIterator(List<NestedInteger> nestedList) {
            // 递归拿元素。
            dfs(nestedList);
        }
    
        // 树的前序遍历。
        private void dfs(List<NestedInteger> nestedList) {
            // 多个平行递归,树就是多支子树递归结构。
            for (NestedInteger nest : nestedList) {
                if (nest.isInteger()) arr.add(nest.getInteger());
                else dfs(nest.getList());
            }
        }
    
        @Override
        public boolean hasNext() {
            return idx < arr.size();
        }
    
        @Override
        public Integer next() {
            int val = idx < arr.size() ? arr.get(idx) : -1;
    
            if (idx < arr.size()) ++idx;
    
            return val;
        }
    
        class NestedInteger {
            List<NestedInteger> nestedList;
            Integer val;
    
            public NestedInteger(List<NestedInteger> nestedList, Integer val) {
                this.nestedList = nestedList;
                this.val = val;
            }
    
            public boolean isInteger() {
                return val != null;
            }
    
            public List<NestedInteger> getList() {
                return nestedList;
            }
    
            public Integer getInteger() {
                return val;
            }
        }
    }
    
    • 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
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    2、栈模拟

    // 迭代 + 栈 实现。
    class NestedIterator2 implements Iterator<Integer> {
        List<Integer> arr = new ArrayList<>();
        int idx = 0;
    
        // 层层嵌套,就像是学过的树结构,integer为叶子节点,list为父节点。
        // 扁平化的过程就像是前序遍历一样。
        public NestedIterator2(List<NestedInteger> nestedList) {
    
            // 根左右
            Stack<NestedInteger> sk = new Stack<>();
            for (int i = nestedList.size() - 1; i >= 0; i--) sk.push(nestedList.get(i));
            NestedInteger root;
            while (!sk.isEmpty()) {
                root = sk.pop();
    
                if (root.isInteger()) arr.add(root.getInteger());
                else {
                    List<NestedInteger> list = root.getList();
                    for (int i = list.size() - 1; i >= 0; i--) sk.push(list.get(i));
                }
            }
        }
    
        @Override
        public boolean hasNext() {
            return idx < arr.size();
        }
    
        @Override
        public Integer next() {
            int val = idx < arr.size() ? arr.get(idx) : -1;
    
            if (idx < arr.size()) ++idx;
    
            return val;
        }
    
        class NestedInteger {
            List<NestedInteger> nestedList;
            Integer val;
    
            public NestedInteger(List<NestedInteger> nestedList, Integer val) {
                this.nestedList = nestedList;
                this.val = val;
            }
    
            public boolean isInteger() {
                return val != null;
            }
    
            public List<NestedInteger> getList() {
                return nestedList;
            }
    
            public Integer getInteger() {
                return val;
            }
        }
    }
    
    • 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
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    3、惰性栈模拟(next时再入栈)

    // 迭代 + 栈 + next时访问元素。
    class NestedIterator3 implements Iterator<Integer> {
        NestedInteger root;
        Stack<NestedInteger> sk = new Stack<>();
    
        // 层层嵌套,就像是学过的树结构,integer为叶子节点,list为父节点。
        // 扁平化的过程就像是前序遍历一样。
        public NestedIterator3(List<NestedInteger> nestedList) {
            // 根左右
            for (int i = nestedList.size() - 1; i >= 0; i--) sk.push(nestedList.get(i));
        }
    
        @Override
        public boolean hasNext() {
            while (!sk.isEmpty() && !sk.peek().isInteger()) {
                root = sk.pop();
    
                List<NestedInteger> list = root.getList();
                for (int i = list.size() - 1; i >= 0; i--) sk.push(list.get(i));
            }
    
            return !sk.isEmpty();
        }
    
        @Override
        public Integer next() {
            return sk.pop().getInteger();
        }
    
        class NestedInteger {
            List<NestedInteger> nestedList;
            Integer val;
    
            public NestedInteger(List<NestedInteger> nestedList, Integer val) {
                this.nestedList = nestedList;
                this.val = val;
            }
    
            public boolean isInteger() {
                return val != null;
            }
    
            public List<NestedInteger> getList() {
                return nestedList;
            }
    
            public Integer getInteger() {
                return val;
            }
        }
    }
    
    • 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
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    总结

    1)问题转换,确认需求,建模(抽象出来),利用已学知识解决(一般需需要变形,或增加一些细节。),是常见的问题解决方案。当然如果问题转换比较巧妙,则属于脑筋急转弯!

    2)树本身就是递归结构,所以树的前序遍历就是多递归,也可以理解为,递归开辟for循环,循环来访问每棵子树。

    3)一题多解,深刻理解树的递归结构,前序遍历的本质,才能对考察的知识点融汇贯通,进而举一反三!

    参考文献

    [1] LeetCode 扁平化嵌套列表迭代器

  • 相关阅读:
    手把手调参最新 YOLOv7 模型 推理部分 - 最新版本(一)
    2023-11-9
    微信小程序--事件
    OpenFeign、Feign以及Ribbon关系介绍
    痞子衡嵌入式:一个关于Segger J-Flash在Micron Flash固定区域下载校验失败的故事(SR寄存器BP[x:0]位)
    计算机毕业设计之java+ssm基于个人需求和地域特色的外卖推荐系统
    GUI编程--PyQt5--QWidget3 控件的交互
    【前端源码解析】数据响应式原理
    【Hack The Box】linux练习-- SneakyMailer
    二叉树的遍历 中序线索二叉树
  • 原文地址:https://blog.csdn.net/qq_43164662/article/details/126881303