问题描述
给定一个二叉树,原地将它展开为链表。
例如,给定二叉树
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);
}
}