要知道这个题目转换为链表肯定是使用“左链”或者“右链”来连接它们,这里我们就使用“右链”。有两种解法。
1.根据后序遍历的特点来改造
我们知道后续遍历的顺序是左子树—>右子树—>根节点。所以我们可以先把左子树变为一个链,然后放到根的右子树上,然后将右子树变为一个链,最后把右子树放到左子树那个链尾上就行了,代码如下:
class Solution {
public void flatten(TreeNode root) {
helper(root);
}
private TreeNode helper(TreeNode root) {
//如果这个节点是叶子或者空,直接返回
if (root == null || root.left == null && root.right == null)
return root;
TreeNode right = helper(root.right); //将右子树变为一个链
TreeNode left = helper(root.left); //将左子树变为一个链
if (left == null) { //如果左子树为空则只需把右子树形成的链连接上就行
root.right = right;
return root;
} else { //左子树不为空
root.left = null; //先把根节点的左子树置为空
root.right = left; //把刚才形成的左子树链接到右子树上
TreeNode result = root;
while (root.right != null) //找到左子树链的链尾节点
root = root.right;
root.right = right; //将右子树链接到左子树链尾上
return result;
}
}
}
2. 非递归的方法
根据方法1我们知道了,其实就是将两个子树改造后进行拼接即可。那有没有一种非递归的方法呢,是有的。我们知道连接的时候最终肯定是将根节点右子树连接到左子树上的最右节点的,那么我们可以先执行这一过程,连接以后根节点的右子树就变成了根节点左子树最右节点的右子树了,那我们再将这个连接后的整个左子树变为根节点的右子树,并继续向下改造这个右子树就行了。画了个简单的图可以看一下:
图中方框起来的节点表示我们要对哪个根节点对应的树进行改造,箭头则是改造的操作。代码如下:
public static void flatten(TreeNode root) {
while (root != null) {
if (root.left != null) {
TreeNode most_right = root.left; // 如果左子树不为空, 那么就先找到左子树的最右节点
while (most_right.right != null) most_right = most_right.right; // 找最右节点
most_right.right = root.right; // 然后将跟的右孩子放到最右节点的右子树上
root.right = root.left; // 这时候跟的右孩子可以释放, 因此令左孩子放到右孩子上
root.left = null; // 将左孩子置为空
}
root = root.right; // 继续改造下一个节点所在的树
}
return;
}
代码参考了zerozone的解答