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

前言

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

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

在这里插入图片描述

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

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;
        }
    }
}

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;
        }
    }
}

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

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

参考文献

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值