Leetcode114. Flatten Binary Tree to Linked List

Leetcode114. Flatten Binary Tree to Linked List

Given a binary tree, flatten it to a linked list in-place.
For example, given the following tree:

    1
   / \
  2   5
 / \   \
3   4   6

The flattened tree should look like:

1
 \
  2
   \
    3
     \
      4
       \
        5
         \
          6

解法一

    1
   / \
  2   5
 / \   \
3   4   6

//将 1 的左子树插入到右子树的地方
    1
     \
      2         5
     / \         \
    3   4         6        
//将原来的右子树接到左子树的最右边节点
    1
     \
      2          
     / \          
    3   4  
         \
          5
           \
            6

 //将 2 的左子树插入到右子树的地方
    1
     \
      2          
       \          
        3       4  
                 \
                  5
                   \
                    6   

 //将原来的右子树接到左子树的最右边节点
    1
     \
      2          
       \          
        3      
         \
          4  
           \
            5
             \
              6         

  ......
public void flatten(TreeNode root) {
    while (root != null) { 
        //左子树为 null,直接考虑下一个节点
        if (root.left == null) {
            root = root.right;
        } else {
            // 找左子树最右边的节点
            TreeNode pre = root.left;
            while (pre.right != null) {
                pre = pre.right;
            } 
            //将原来的右子树接到左子树的最右边节点
            pre.right = root.right;
            // 将左子树插入到右子树的地方
            root.right = root.left;
            root.left = null;   //注意将左子树置空!
            // 考虑下一个节点
            root = root.right;
        }
    }
}

解法二 变形的后序排序

基本思路是直接在原来的节点上改变指向

题意是将二叉树通过右指针,组成一个链表。1 -> 2 -> 3 -> 4 -> 5 -> 6

我们知道题目给定的遍历顺序其实就是先序遍历的顺序,所以我们能不能利用先序遍历的代码,每遍历一个节点,就将上一个节点的右指针更新为当前节点。

先序遍历的顺序是1 2 3 4 5 6。
遍历到2,把1的右指针指向2。1 -> 2 3 4 5 6。
遍历到3,把2的右指针指向3。1 -> 2 -> 3 4 5 6。
... ...

问题是我们把1的右指针指向2,那么1的原本的右孩子就丢失了,也就是5就找不到了。

解决方法的话,我们可以逆过来进行。

依次遍历6 5 4 3 2 1,然后每遍历一个节点就将当前节点的右指针更新为上一个节点。
遍历到5,把5的右指针指向6。6 <- 5 4 3 2 1。
遍历到4,把4的右指针指向5。6 <- 5 <- 4 3 2 1。
... ...

这样就不会有丢失孩子的问题了,因为更新当前的右指针的时候,当前节点的右孩子已经访问过了。

而6 5 4 3 2 1的遍历顺序其实变形的后序遍历,遍历顺序是右子树->左子树->根节点。

变形的后序遍历的代码

public void postorder(TreeNode<T> root){
    if (root == null)
        return;
    postorder(root.right);
    postorder(root.left); 
    System.out.print(root.data);

}

我们不再是打印根节点,而是利用一个全局变量pre,更新当前根节点的右指针为pre,左指针为null

private TreeNode pre = null;

public void flatten(TreeNode root) {
    if (root == null)
        return;
    flatten(root.right);
    flatten(root.left);
    root.right = pre;
    root.left = null;
    pre = root;
}

相应的左孩子也要置为null,同样的也不用担心左孩子丢失,因为是后序遍历,左孩子已经遍历过了。

迭代形式:

public void flatten(TreeNode root) { 
    Stack<TreeNode> toVisit = new Stack<>();
    TreeNode cur = root;
    TreeNode pre = null;

    while (cur != null || !toVisit.isEmpty()) {
        while (cur != null) {
            toVisit.push(cur); // 添加根节点
            cur = cur.right; // 递归添加右节点
        }
        cur = toVisit.peek(); // 已经访问到最右的节点了
        // 在不存在左节点或者右节点已经访问过的情况下,访问根节点
        if (cur.left == null || cur.left == pre) {
            toVisit.pop(); 
            /**************修改的地方***************/
            cur.right = pre;
            cur.left = null;
            /*************************************/
            pre = cur;
            cur = null;
        } else {
            cur = cur.left; // 左节点还没有访问过就先访问左节点
        }
    } 
}

解法三

发布了82 篇原创文章 · 获赞 7 · 访问量 4999

猜你喜欢

转载自blog.csdn.net/magic_jiayu/article/details/104300593