题目:
给定一个二叉树,将该树的节点展开成链表结构,并依次放到树的右节点上,(顺序为前序遍历的顺序),每个节点的左子树都置为null。
思路:
方法一
我们首先能想到的就是前序遍历一遍二叉树,将节点放入到一个list
集合中,然后依次更改原二叉树的节点指向,使其成为一个链表结构
以下为代码+注释,结合代码和注释应该好理解一点:
//首先定义TreeNode节点
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int val){
this.val = val;
}
}
public TreeNode flatten(TreeNode root){
if(root == null)
return root;
List<TreeNode> list = new ArrayList<>();
//将二叉树前序遍历的节点依次放入list集合中
preorder(root, list);
int len = list.size();
for (int i = 0; i < len - 1; i++) {
//取出当前节点,重新调整左右子树的节点值
TreeNode cur = list.get(i);
//将当前节点的左节点置为null
cur.left = null;
//该节点在list集合中的下一个节点就是它的右子树节点
cur.right = list.get(i + 1);
}
return root;
}
// 前序遍历二叉树
public void preorder(TreeNode root, List list) {
if (root != null) {
list.add(root);
preorder(root.left, list);
preorder(root.right, list);
}
}
方法二
能不能找到一种不使用额外空间,让空间复杂度降到O(1)的做法?
当然有。
思考一下,将一个二叉树展开为链表,假设一个当前节点cur
,因为前序遍历的顺序就是:头节点,左子树,右子树。
那么展开其实就是将当前节点cur
的左子树上前序遍历的最后一个节点指向了cur
的右子树的第一个节点(主要思想),之后再将指针重新赋值
以下为代码+注释:
public void flatten(TreeNode root) {
if(root == null)
return;
// 因为每个节点的左子树前序遍历的最后一个节点的下一个就是右子树的第一个节点,
// 因此可以在递归的时候就做好记录并直接进行连接
// 先设置一个cur指针指向当前节点
TreeNode cur = root;
while(cur != null){
if(cur.left != null){
// 记录当前节点的下一个节点,最后要用
TreeNode next = cur.left;
// 设置一个前驱节点,最后要让它指向当前节点的右节点
TreeNode pre = next;
// 不停遍历直到pre指向当前节点左子树的最后一个遍历到的节点
while(pre.right != null){
pre = pre.right;
}
// 将前驱节点的下一个指向当前节点的右子树第一个节点
pre.right = cur.right;
// 当前节点的左子树设置为null
cur.left = null;
// 当前节点的右子树节点指向前驱节点
cur.right = next;
}
// 当前节点继续向下走
cur = cur.right;
}
return root;
}
以上所有文字均为我本人所写,我也是在不断学习之中,如有错误,欢迎指正!