114. 二叉树展开为链表
题目:
给定一个二叉树,原地将它展开为一个单链表,例如:
1
/ \
2 5
/ \ \
3 4 6
展开之后为:
1
\
2
\
3
\
4
\
5
\
6
分析:
看到这道题自然而然会想到二叉树的三种遍历方式:先序遍历、中序遍历、后序遍历。而且从样例可以看出转换后的单链表是按照先序遍历的方式生成的,所以本题最为简单的做法就是借助先序遍历,依次将树的所有节点保存下来,再将其链接为一个单链表,时间和空间复杂度都为O(n)。
这种方法在此就不细说了,接下来我们考虑一个空间复杂度为O(1)的做法。我们先从简单的情况进行分析:
如果树的结构如下:
1
/ \
2 3
我们是不是可以想到最快的方法就是将根节点的右子节点接在左子节点的右子节点上,然后将左子树放在根节点的右子树的位置,最后将左子树置空:
1
\
2
\
3
如果树的左子节点为空:
1
\
2
那么我们不用做任何操作,直接返回即可。
如果树的右子节点为空:
1
/
2
那么我们只用将左子节点放在树的右子节点处,然后将左子节点置空即可:
1
\
2
看完了上面的几种情况,我们就可以考虑,采用递归的方法,对根节点的所有左右子树按如上方法进行操作,但是有一点需要注意,因为最后生成的单链表是按照先序遍历进行排列的,所以在第一种情况将右子树放在左子树的右子树的操作需要找到左子树按照先序遍历访问时最后的一个节点,即左子树的最右叶子节点。
代码如下:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
void flatten(TreeNode* root) {
if (root == nullptr)
{
return;
}
if (root->left != nullptr) //左子树不为空
{
if (root->right != nullptr) //左右子树都不为空
{
TreeNode* root_temp = root;
root_temp = root_temp->left;
while (root_temp->right != nullptr) //找到左子树的最右叶子节点
{
root_temp = root_temp->right;
}
root_temp->right = root->right;
root->right = root->left;
root->left = nullptr;
}
else //右子树为空
{
root->right = root->left;
root->left = nullptr;
}
flatten(root->right);
}
else //左子树为空
{
flatten(root->right);
}
}
};