114:二叉树展开为链表

问题描述

给定一个二叉树,原地将它展开为链表。

例如,给定二叉树

    1
   / \
  2   5
 / \   \
3   4   6

将其展开为:

1
 \
  2
   \
    3
     \
      4
       \
        5
         \
          6

思路

我们发现,如果从最底层的结点开始,都把它的右孩子插入在左孩子的最后一个结点处,然后再递归的调整结果来的这棵树,则整棵树满足题意。为啥?因为最左下的子树我们都调整好了。也可以认为这是中序遍历法。(方法一)
好麻烦,看不懂,咋办?用辅助空间。我们发现展开之后是个先序遍历序列。我们先先序遍历一把,按照访问的先后顺序存储到一个ArrayList中,然后直接在ArrayList里改他们的结点指向即可。(方法二)
方法一提到了中序遍历,那么先序遍历行不行呢?当然可以。理论依据呢?因为先序遍历是先访问根结点,再遍历左子树和右子树。如果我们把右子树直接接在左子树的该接入的位置(根据中-左-右)来说,应该接在左子树的最右下结点。我们写了个函数来找最右下结点。由于操作之后,左子树为空,所以我们只需要递归的生成右子树即可。自顶向下的方法。(方法三)
既然方法二和方法三都强调了顺序。那么我们可不可以设置一个全局的指针来指示上一个结点呢?当然可以。只需要简单的先序遍历,我们就能获得last指针。然后通过last改变指向即可。等等?断链之后,怎么保存原来结点的状态呢?没所谓的,我们可以用cache把右孩子给保存下来,就不用担心了。(方法四)

方法一

class Solution {
    public void flatten(TreeNode root) {
        /* 中序遍历法 */
        if(root == null) return; // 循环退出条件
        flatten(root.left); // 递归遍历左子树
        if(root.right == null){ // 如果右子树为空,则直接把左子树拿过来
            root.right = root.left;
            root.left = null;
        }else{ // 右子树不为空,则找到它的根结点除了根结点的右子树之外的最后一个结点
            TreeNode cur = root.right;
            root.right = null; // 首先将右子树断链,这样才能找最后一个结点
            TreeNode last = getLast(root);
            root.right = root.left; // 先将左子树移过来
            root.left = null; // 再将左子树断链
            last.right = cur; // 最后把右子树接到最后一个结点后面
        }
        flatten(root.right); // 递归的处理右子树
    }
    private TreeNode getLast(TreeNode root){
        // 层序遍历拿到最后一个结点
        Queue<TreeNode> queue = new LinkedList<>();
        if(root == null) return null;
        queue.add(root);
        TreeNode res = null;
        while(queue.size() > 0){
            if(queue.peek().left != null) queue.add(queue.peek().left);
            if(queue.peek().right != null) queue.add(queue.peek().right);
            res = queue.poll();
        }
        return res;
    }
}

方法二

class Solution {
    ArrayList<TreeNode> data = new ArrayList<>();
    public void flatten(TreeNode root) {
        initData(root);
        for(int i = 0; i < data.size()-1; i++){
            data.get(i).left = null;
            data.get(i).right = data.get(i+1);
        }
    }
    private void initData(TreeNode root){
        if(root == null) return;
        data.add(root);
        initData(root.left);
        initData(root.right);
    }
}

方法三

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

    }
    private TreeNode getPre(TreeNode root){
        if(root == null) return null;
        while(root.right != null) root = root.right;
        return root;
    }
}

方法四

class Solution {
    TreeNode last;
    public void flatten(TreeNode root) {
        if(root == null) return;
        TreeNode cache = root.right;
        if(last == null){
            last = root;
            flatten(root.left);
        }else{
            last.right = root;
            last.left = null;
            last = root;
            flatten(root.left);
        }
        flatten(cache);
    }
}
发布了464 篇原创文章 · 获赞 21 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/weixin_41687289/article/details/105430626