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

解答
解法一:前序遍历
从图中可以看出,链表是按照前序遍历的顺序转换的。
所以很容易想到前序遍历的方式。
但要注意一点:遍历结点的左子树过程中结点的右子树会发生改变,所以需要暂存右子树结点。
代码
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
TreeNode last = null;
public void flatten(TreeNode root) {
if(root == null) return;
TreeNode oldLeft = root.left;
TreeNode oldRight = root.right;
if(last != null) {
last.left = null;
if(last.right != root) {
root.right = last.right;
last.right = root;
}
}
last = root;
flatten(oldLeft);
flatten(oldRight);
}
}
更精简的写法
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
TreeNode pre = null;
public void flatten(TreeNode root) {
if (root == null) return;
if (pre != null) {
pre.left = null;
pre.right = root;
}
pre = root;
TreeNode copyRight = root.right;
flatten(root.left);
flatten(copyRight);
}
}
结果

解法二:倒着的前序遍历
既然正序的前序遍历会改变右子树,从而必须要暂存右子树。
那么我们可以倒着来,先展开右子树,再展开左子树,最后让根节点与这两个子链表链接起来。
顺序如下:右子树展开 -> 左子树展开并与右子树链接 -> 当前节点与左子树链接。
代码
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
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;
}
}
结果

解法三:后序遍历
另一种去除原来必须暂存右子树缺陷的方法就是采用后序遍历了。
主要思路是:
- 将当前节点的右子树放到左子树最右节点的右边。
- 然后将当前结点的右指针指向左子树,并把左指针置为空(避免环)。
- 这样一轮下来,左子树链表段的头和尾就确定了。
- 之后就是递归将链表段中间的结点转换。
- 当前链表段转换完毕后就可以根据该链表段尾部的右指针找到未转换的右子树了。
- 之后对右子树循环上述过程,最终就会转换成一条链表了。
递归代码
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public void flatten(TreeNode root) {
if(root == null) return;
flatten(root.left);
flatten(root.right);
if(root.left != null) {
TreeNode mostRight = root.left;
while(mostRight.right != null) mostRight = mostRight.right;
mostRight.right = root.right;
root.right = root.left;
root.left = null;
}
}
}
非递归代码
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public void flatten(TreeNode root) {
if(root == null) return;
while(root != null) {
if(root.left != null) {
TreeNode mostRight = root.left;
while(mostRight.right != null) mostRight = mostRight.right;
mostRight.right = root.right;
root.right = root.left;
root.left = null;
}
root = root.right;
}
}
}
结果

本文详细介绍了三种将二叉树转换为链表的方法:前序遍历、倒序前序遍历及后序遍历。每种方法都附有代码实现,帮助读者深入理解算法原理。
1315

被折叠的 条评论
为什么被折叠?



