Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
不是因为看到了希望才坚持,而是因为坚持了才能看到希望。共勉
每日刷题第60天 2021.03.10
589. N 叉树的前序遍历
- leetcode原题链接:leetcode-cn.com/problems/n-…
- 难度:简单
- 方法:递归、迭代
题目描述
- 给定一个
n叉树的根节点root,返回 其节点值的 前序遍历 。 n叉树在输入中按层序遍历进行序列化表示,每组子节点由空值null分隔(请参见示例)。
示例
- 示例1
输入: root = [1,null,3,2,4,null,5,6]
输出: [1,3,5,6,2,4]
- 示例2
输入:root = [1,null,2,3,4,5,null,null,6,7,null,8,null,9,10,null,null,11,null,12,null,13,null,null,14]
输出:[1,2,3,6,7,11,14,4,8,12,5,9,13,10]
提示
- 节点总数在范围
[0, 104]内 0 <= Node.val <= 104- n 叉树的高度小于或等于
1000
思路分析
递归解法(dfs)
- 首先要会二叉树的前序遍历,那么多叉树的前序遍历就会了
- 前序遍历:根、左节点、右节点
- 中序遍历:左节点、根、右节点
- 后序遍历:左节点、右节点、根
- 对于一棵树来说,每个节点都相当于是根节点,其有属于自己的左子树和右子树,那么问题就可以简化为:重复求解 ==> 每个节点的打印 <=> 根节点(每个树)的打印
- 对于递归模版的前中后序遍历,只需要改变根节点的打印顺序即可。
- 模版代码
// 预处理
let ans = [];
if(root == null) return ans;
function traversal(node) {
if (node == null) return;
ans.push(node); // 中
traversal(node.left); // 左
traversal(node.right); // 右
}
traversal(root)
递归写法的步骤
- 确定递归函数的参数和返回值(有时候可能是全局的,也有可能是局部的)
- 确定哪些参数是递归中需要返回处理的,哪些参数是全局访问的。
- 确定终止条件
- 如果不写终止条件,会出现栈溢出的错误🙅,操作系统也是用一个栈的结构来保存每一层递归的信息,如果递归没有终止,操作系统的内存栈就会溢出。
- 确定单层递归的逻辑
- 将大问题转换成为多个重复的子问题,书写单层逻辑。
迭代解法(非递归解法)
- 分析:递归的实现就是每一次递归调用会把相关的函数局部变量、参数值和返回地址等压入栈中,然后递归返回的时候,从栈顶弹出上一次递归的各项参数。
拓展:二叉树的前序、中序、后序迭代法
- 前序迭代:先访问的是根节点,需要先处理的也是根节点(较简单)
- 中序迭代(稍难):先访问的是根节点,但是先处理的不再是根节点,而是左节点
- 后序迭代:先访问的是根节点,但是先处理的也不是根节点,而是左节点
- 先序遍历是中左右,后续遍历是左右中,只需要调整一下先序遍历的代码顺序,就变成中右左的遍历顺序,然后在反转result数组,输出的结果顺序就是左右中了。
AC代码
n叉树的前序遍历
/**
* // Definition for a Node.
* function Node(val, children) {
* this.val = val;
* this.children = children;
* };
*/
/**
* @param {Node|null} root
* @return {number[]}
*/
var preorder = function(root) {
// 模拟栈的写法
// map 删除集合中的元素的方法map.delete()
// 记录最终的结果的数组
let ans = [];
// 模拟栈数组
let stack = [];
// map集合记录当前有几个子节点已经被遍历过
let nextIndex = new Map();
let node = root;
if(root == null) return ans;
while(stack.length || node) {
// 预判断:处理根节点为空的情况
// console.log(node)
// 循环查找所有的左边节点
while(node){
// 循环遍历到没有子节点
ans.push(node.val);
stack.push(node);
if(node.children.length == 0){
break;
}
nextIndex.set(node, 1);
node = node.children[0];
}
// 下一个节点
node = stack[stack.length - 1];
// 查找下一个子节点
const len = node.children.length;
const i = nextIndex.get(node);
if(i < len){
// 还有子节点没有遍历
// 子节点入栈
nextIndex.set(node, i + 1);
node = node.children[i];
}else {
stack.pop();
nextIndex.delete(node);
node = null;
}
}
return ans;
};
总结
树🌲dfs通用模版
- 树的中序、前序、后序迭代方法实现不太相同