LeetCode - 590 - N叉树的后续遍历(n-ary-tree-postorder-traversal)

一 目录

不折腾的前端,和咸鱼有什么区别

目录
一 目录
二 前言
三 解题及测试
四 LeetCode Submit
五 解题思路
六 进一步思考

二 前言

  • 难度:简单
  • 涉及知识:树
  • 题目地址:https://leetcode-cn.com/problems/n-ary-tree-postorder-traversal/
  • 题目内容
给定一个 N 叉树,返回其节点值的后序遍历。

例如,给定一个 3叉树 :

  1
/ | \
3 2 4
/ \
5 6

返回其后序遍历: [5,6,3,2,4,1].

说明: 递归法很简单,你可以使用迭代法完成此题吗?

三 解题及测试

小伙伴可以先自己在本地尝试解题,再回来看看 jsliang 的解题思路。

  • LeetCode 给定函数体
/**
* // Definition for a Node.
* function Node(val,children) {
* this.val = val;
* this.children = children;
* };
*/
/**
* @param {Node} root
* @return {number[]}
*/
var postorder = function(root) {

};

根据上面的已知函数,尝试破解本题吧~

确定了自己的答案再看下面代码哈~

index.js

/**
* // Definition for a Node.
* function Node(val,children) {
* this.val = val;
* this.children = children;
* };
*/
/**
* @name N叉树的后序遍历
* @param {Node} root
* @return {number[]}
*/
const postorder = (root, result = []) => {
if (!root) {
return [];
}
if (root.children) {
for (let i = 0; i < root.children.length; i++) {
postorder(root.children[i], result);
}
}
result.push(root.val);
return result;
};

const root = {
val: 1,
children: [
{
val: 3,
children: [
{ val: 5, children: null },
{ val: 6, children: null },
],
},
{ val: 2, children: null },
{ val: 4, children: null },
],
};

console.log(postorder(root));

node index.js 返回:

[ 5, 6, 3, 2, 4, 1 ]

四 LeetCode Submit

Accepted
* 37/37 cases passed (88 ms)
* Your runtime beats 98.79 % of javascript submissions
* Your memory usage beats 100 % of javascript submissions (37.5 MB)

五 解题思路

树的先序遍历和后序遍历,是怎么通过递归得出的呢?

  1. 先序:通过外层的数组,逐一获取遍历的元素。
  2. 后序:通过内部的数组,逐一传递到外部。

说地再多不如看代码:

初始代码:

const postorder = (root) => {
const ergodic = (root, result = []) => {
if (!root) {
return [];
}
if (root.children) {
for (let i = 0; i < root.children.length; i++) {
ergodic(root.children[i], result);
}
}
result.push(root.val);
return result;
};
return ergodic(root);
};

这份代码 Submit 提交是 OK 的:

Accepted
* 37/37 cases passed (88 ms)
* Your runtime beats 98.79 % of javascript submissions
* Your memory usage beats 100 % of javascript submissions (37.5 MB)

它的思路在于,通过一开始默认的空数组,不断【返回】上一层,往里面添加内容,最终返回后序遍历需要的结果。

如果你还不够清晰,不急,咱们先优化下代码,说不定你会有灵感:

第一次优化:精简代码

const postorder = (root, result = []) => {
if (!root) {
return [];
}
if (root.children) {
for (let i = 0; i < root.children.length; i++) {
postorder(root.children[i], result);
}
}
result.push(root.val);
return result;
};

在这份代码中,它主要功能:

  1. 第一个 if 判断数组是不是到了底部,如果是,那么返回 [] 数组。
  2. 第二个 if 判断数组是不是还未展开完毕,如果是,则逐层遍历它的 children,将 result 传递出去。
  3. 最后, result 添加这次节点的 val 值,并返回出去。

我们不妨加两个 console.log(),小伙伴们会观察地更加仔细:

const postorder = (root, result = []) => {
if (!root) {
return [];
}
if (root.children) {
for (let i = 0; i < root.children.length; i++) {
postorder(root.children[i], result);
}
}
result.push(root.val);
console.log('------');
console.log(root);
console.log(result);
return result;
};

它的打印记录为:

------
{ val: 5, children: null }
[ 5 ]
------
{ val: 6, children: null }
[ 5, 6 ]
------
{ val: 3,
children: [ { val: 5, children: null }, { val: 6, children: null } ] }
[ 5, 6, 3 ]
------
{ val: 2, children: null }
[ 5, 6, 3, 2 ]
------
{ val: 4, children: null }
[ 5, 6, 3, 2, 4 ]
------
{ val: 1,
children:
[ { val: 3, children: [Array] },
{ val: 2, children: null },
{ val: 4, children: null } ] }
[ 5, 6, 3, 2, 4, 1 ]

可以清楚的看到,它按照我们的想法进行操作了。

当然,小伙伴们可以参考下上篇文章:589-N叉树的前序遍历(自行翻找 GitHub 或者公众号,这里不贴链接了),进行进一步的了解。

六 进一步思考

正如题目所说,我们不能仅仅只会递归,还可以尝试下迭代:

const postorder = (root) => {
if (!root) {
return [];
}
const result = [];
const tempRoot = [root];
while (tempRoot.length) {
const current = tempRoot.pop();
result.unshift(current.val);
if (current.children) {
for (let i = 0; i < current.children.length; i++) {
tempRoot.push(current.children[i]);
}
}
}
return result;
};

在这份代码中,做的操作有:

  1. 判断是否传入的为 [] 空树,如果是,则返回 []
  2. root 变成一个数组 [root] 设为 tempRoot,进行遍历操作。
  3. 循环遍历 tempRoot.length,直到所有内容都遍历完毕。
  4. 定义 current 获取 tempRoot 的最末尾元素。
  5. 每次 result 获取当前元素的 val 值,将其塞入末尾。
  6. 判断 currentchildren 里面是否还有值,有的话就遍历它,将其推入 tempRoot
  7. 循环步骤 4 - 步骤 6,直到当前元素都是最根层次的元素。
  8. 最终返回 result 值。

Submit 提交结果:

Accepted
* 37/37 cases passed (116 ms)
* Your runtime beats 97.57 % of javascript submissions
* Your memory usage beats 100 % of javascript submissions (37.4 MB)

这样,我们就完成了 N叉树的后序遍历 操作啦~


不折腾的前端,和咸鱼有什么区别!

jsliang 会每天更新一道 LeetCode 题解,从而帮助小伙伴们夯实原生 JS 基础,了解与学习算法与数据结构。

浪子神剑 会每天更新面试题,以面试题为驱动来带动大家学习,坚持每天学习与思考,每天进步一点!

扫描上方二维码,关注 jsliang 的公众号(左)和 浪子神剑 的公众号(右),让我们一起折腾!

jsliang 的文档库 由 梁峻荣 采用 知识共享 署名-非商业性使用-相同方式共享 4.0 国际 许可协议进行许可。
基于https://github.com/LiangJunrong/document-library上的作品创作。
本许可协议授权之外的使用权限可以从 https://creativecommons.org/licenses/by-nc-sa/2.5/cn/ 处获得。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值