一、题目描述
给你二叉树的根结点 root ,请你将它展开为一个单链表:
(1)展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null 。
(2)展开后的单链表应该与二叉树 先序遍历 顺序相同。
二、解题思路
(1)首先中序遍历该二叉树,将遍历的每个节点保存在ArrayList集合中,然后循环遍历该集合同时修改每个节点的左右孩子。
class Solution{
public void flatten(TreeNode root) {
if (root == null) {
return;
}
List<TreeNode> nodePath = new ArrayList<>();
//先序遍历,保存每个TreeNode节点
traversal(root, nodePath);
//遍历保存节点的数组,修改每个节点的左右孩子
for (int i = 1; i < nodePath.size(); i++) {
TreeNode pre = nodePath.get(i - 1);
TreeNode cur = nodePath.get(i);
pre.left = null;
pre.right = cur;
}
}
//中序遍历
public void traversal(TreeNode root, List<TreeNode> nodePath) {
if (root == null) {
return;
}
nodePath.add(root);
traversal(root.left, nodePath);
traversal(root.right, nodePath);
}
}
(2)大致思路:边遍历二叉树,边修改每个节点的左右孩子。
细节:1)如果按照先序遍历的从上往下的顺序对每个节点的左右孩子进行修改,必定会造成节点的左子树(右子树)丢失的情况,所以应当逆序(即从下往上进行构造),保证构造当前节点时,其右子树已经构造好,然后其做指针指为Null,右指针直接指向上一步已构造好的右子树即可
2)先序遍历若为:123456,则从下往上构造的构造顺序必为654321,所以对二叉树的遍历顺序应该与先序遍历顺序相反,即:右左中。
class Solution{
//注意这里全局变量设计的巧妙之处:递归回到上一层时,全局变量的值不会回到该层时变量的状态,还是保持当前的值不变
TreeNode pre = null;
public void flatten1(TreeNode root) {
postOrderTraverse(root);
}
public void postOrderTraverse(TreeNode root) {
if (root == null) return;
// 右->左->中:从下往上构建二叉树(为什么是该顺序?因为原来顺序为中左右,这是正序构建,那么逆序构建时,最先被构建的必定为右左中的右)
postOrderTraverse(root.right);
postOrderTraverse(root.left);
root.left = null;
root.right = pre;
pre = root;
}
}
三、知识点
递归中的全局变量与作为函数参数的局部变量差别:
(1)全局变量形式,递归返回上一层时,其值不会自动变为在上一层时该值所处状态
如有一全局变量sum,递归前:sum=10,递归后:sum=20,当前程序回到递归前的状态时,sum依然为20
(2)参数形式局部变量:因每一层递归调用时,当前所有参数的状态都会被保存下来,然后进入下一层递归,当递归回退时,会将上一次保存的状态取出来继续使用,所以其值会自动回到上一层时的状态。
如有一全局变量sum,递归前:sum=10,递归后:sum=20,当前程序回到递归前的状态时,sum变回原来的状态,即sum=10