【刷爆力扣之589-590. N叉树的前序遍历和后序遍历】

589:N叉树的前序遍历

这道题需要灵活的理解前序遍历的规则,从二叉树到N叉树,原则都是统一的,因此我们可以借鉴二叉树的前序遍历方式,使用递归 以及迭代两种方式完成N叉树的前序遍历

方法一:递归

思路:

递归思路比较简单,N 叉树的前序遍历与二叉树的前序遍历的思路和方法基本一致,可以参考「144. 二叉树的前序遍历」的方法,每次递归时,先访问根节点,然后依次递归访问每个孩子节点即可。

java 复制代码
public List<Integer> preorder(Node root) {
    List<Integer> res = new ArrayList<>();
    // 调用递归函数
    doPreorder(root, res);
    return res;
}

private void doPreorder(Node node, List<Integer> list) {
    if (node == null) {
        return;
    }
    list.add(node.val);
    // 遍历当前节点的子节点,递归执行
    for (Node child : node.children) {
        doPreorder(child, list);
    }
}

方法二:迭代

思路:

在前序遍历中,我们会先遍历节点本身,然后从左向右依次先序遍历该每个以子节点为根的子树,此时利用 先进后出的原理,依次从右向左将子节点入栈,这样出栈的时候即可保证从左向右依次遍历每个子树。

首先把根节点入栈,因为根节点是前序遍历中的第一个节点。随后每次我们从栈顶取出一个节点 u,它是我们当前遍历到的节点,并把 u 的所有子节点从右向左逆序压入栈中,这样出栈的节点则是顺序从左向右的。

java 复制代码
public List<Integer> preorder(Node root) {
    List<Integer> res = new ArrayList<>();
    if (root == null) {
        return res;
    }
    // 前序遍历需要的栈数据结构
    Stack<Node> stack = new Stack<>();
    stack.push(root);
    while (!stack.isEmpty()) {
        Node pop = stack.pop();
        res.add(pop.val);
        if (!pop.children.isEmpty()) {
            // 当前节点的孩子需要从后往前入栈,才能从前往后出栈实现前序遍历
            // 从右向左逆序压入栈中
            for (int i = pop.children.size() - 1; i >= 0; i--) {
                stack.push(pop.children.get(i));
            }
        }
    }
    return res;
}

590:N叉树的后序遍历

方法一:递归

思路:

递归思路比较简单,NNN 叉树的前序遍历与二叉树的后序遍历的思路和方法基本一致,可以参考「145. 二叉树的后序遍历」的方法,每次递归时,先递归访问每个孩子节点,然后再访问根节点即可。

java 复制代码
// 递归实现
public List<Integer> postorder(Node root) {
    List<Integer> res = new ArrayList<>();
    doPostorder(root, res);
    return res;
}

private void doPostorder(Node node, List<Integer> res) {
    if (node == null) {
        return;
    }
    node.children.forEach(child -> {
        doPostorder(child, res);
    });
    res.add(node.val);
}

方法二:迭代

思路:

在后序遍历中,我们会先从左向右依次后序遍历每个子节点为根的子树,再遍历根节点本身。此时利用栈先进后出的原理,依次从右向左将子节点入栈,这样出栈的时候即可保证从左向右依次遍历每个子树。

首先把根节点入栈,因为根节点是前序遍历中的第一个节点。随后每次我们找到栈顶节点 u,如果当前节点的子节点没有遍历过,则应该先把 u 的所有子节点从右向左逆序压入栈 中,这样出栈的节点则是顺序从左向右的,同时对节点 u 进行标记,表示该节点的子节点已经全部入栈;如果当前节点 u 为叶子节点或者当前节点的子节点已经全部遍历过,则从栈中弹出节点 u,并记录节点 uuu 的值。

java 复制代码
// 迭代实现
public List<Integer> postorder2(Node root) {
    List<Integer> res = new ArrayList<>();
    if (root == null) {
        return res;
    }
    Stack<Node> stack = new Stack<>();
    // 标记节点是否被处理
    List<Node> visited = new ArrayList<>();
    stack.push(root);
    while (!stack.isEmpty()) {
        Node peek = stack.peek();
        // 如果当前节点没有孩子,或者当前节点已经被标记(说明子节点已经处理完了,可以处理当前节点了)
        if (peek.children.isEmpty() || visited.contains(peek)) {
            Node pop = stack.pop();
            res.add(pop.val);
            continue;
        }
        for (int i = peek.children.size() - 1; i >= 0; i--) {
            stack.push(peek.children.get(i));
            // 标记当前节点的所有子节点已经全部入栈
            visited.add(peek);
        }
    }
    return res;
}

方法三:利用前序遍历反转

前序遍历为中 => 左 => 右

后序遍历为 左 => 右 => 中

因此,我们可以使用前序遍历先构造一个 中 => 右 => 左 的结果集合,然后将该结果集合翻转得到后序遍历的结果,那么正常的前序遍历 中 => 左 => 右 怎么得到 中 => 右 => 左 的结果集合呢?

其实, 中 => 左 => 右 的遍历方式是因为我们在将中间节点的左右节点压栈时使用的是先压入右节点,再压入左节点的方式 ,那么我们想要得到 中 => 右 => 左 的结果集合,只需要在压入中间节点左右节点时先压入左节点,再压入右节点即可!

java 复制代码
// 利用前序遍历反转
public List<Integer> postorder3(Node root) {
    List<Integer> res = new ArrayList<>();
    if (root == null) {
        return res;
    }
    Stack<Node> stack = new Stack<>();
    stack.push(root);
    while (!stack.isEmpty()) {
        Node pop = stack.pop();
        res.add(pop.val);
        if (!pop.children.isEmpty()) {
            // 先压入左节点,再压入右节点
            for (Node child : pop.children) {
                stack.push(child);
            }
        }
    }
    // 翻转得到后序遍历的结果
    Collections.reverse(res);
    return res;
}

部分解释来源于力扣题解

. - 力扣(LeetCode)

代码均为原创!

相关推荐
GreenTea3 小时前
vLLM 与 SGLang KV Cache 底层实现机制深度调研报告
前端·后端·算法
Bode_20023 小时前
多资源规划(含生产调度、库存管理及产能规划)的创新优化算法
算法·调度
土司大王4 小时前
LeetCode hot100——35.搜索插入位置:Java 二分模板、左闭右开区间与插入点分析
java·算法·leetcode
微三云生态系统架构师-彭丹4 小时前
远方好物S2B2C系统架构:一级分销与保证金托管的合规技术实现
人工智能·算法
土司大王4 小时前
LeetCode hot100——34.在排序数组中查找元素的第一个和最后一个位置:Java 二分模板、边界分析
java·算法·leetcode
罗西的思考6 小时前
机器人模型(WM / WAM / VLA)综合分析与对比:从「看」到「想」再到「做」
人工智能·算法·机器学习
小哈里7 小时前
【知识】从学科到实践:自然・工程・社科・人文|算法・研发・产品・品牌设计
程序人生·算法·产品·设计·工程
小π军7 小时前
最大重叠区间数量
数据结构·算法
镜像视界(浙江)科技有限公司8 小时前
《视频孪生之上:二维展示终结,三维空间计算重构城市逻辑》——跨摄像连续表达 × 三角测量厘米级定位 × 动态轨迹建模,构建新一代城市空间
大数据·人工智能·算法·矩阵·音视频·空间计算
a187927218318 小时前
【算法】双指针与滑动窗口(二):滑动窗口——吃进、判定、吐出
算法·leetcode·双指针·滑动窗口·原理·模板·算法讲解