给定一个二叉树,原地将它展开为链表。
例如,给定二叉树
1
/ \
2 5
/ \ \
3 4 6
将其展开为:
1
\
2
\
3
\
4
\
5
\
6
其展开就是一个前序遍历
可以发现展开的顺序其实就是二叉树的先序遍历。算法和 94 题中序遍历的 Morris 算法有些神似,我们需要两步完成这道题。
将左子树插入到右子树的地方
将原来的右子树接到左子树的最右边节点
考虑新的右子树的根节点,一直重复上边的过程,直到新的右子树为 null
可以看图理解下这个过程。
可以看图理解下这个过程。
1
/ \
2 5
/ \ \
3 4 6
//将 1 的左子树插入到右子树的地方
1
\
2 5
/ \ \
3 4 6
//将原来的右子树接到左子树的最右边节点
1
\
2
/ \
3 4
\
5
\
6
//将 2 的左子树插入到右子树的地方
1
\
2
\
3 4
\
5
\
6
//将原来的右子树接到左子树的最右边节点
1
\
2
\
3
\
4
\
5
\
6
代码如下:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
void flatten(TreeNode* root) {
while(root)//一直以右子树节点为root
{
if(root->left==NULL)root=root->right;//如果当前的左子树为空,则
else
{
//找到左子树最右边的节点
TreeNode *pre=root->left;
while(pre->right!=NULL)
{
pre=pre->right;
}
//将原来的右子树接到左子树的最右边节点
pre->right = root->right;//这个的意思将root->right赋值个pre->right.所以是将pre->right指向根节点的右子树
//将左子树插入到右子树的地方
root->right = root->left;
root->left = NULL;
// 考虑下一个节点
root = root->right;//即考虑下一个节点,即上面的图中将234这个
}
}
}
};
题目要求原地展开为链表。原地的意思,一个是展开的结果,反应在传入参数,另一个是不能使用容器。in-place
的意思可能更多说的是直接在原来的节点上改变指向,空间复杂度并没有要求。所以这道题也可以用递归解一下。
所以前序遍历标准套路,使用栈、队列存储节点的方案,就不符合题目要求了。
对于每个点来说,将其左边的left置为NULL,而将左边的插入到节点的右边、
递归是一步一步向下的,而且是每个点都是一个重复,所以只需要考虑根节点的情况,根据例子,将节点的左边转为链表,右边也转为链表,然后让左边的链表的表尾接上右边链表的表头,以根节点为讨论的对象,然后将根节点的的left放到right的下边,然后将根节点的left置为NULL,其他点也是重复这个动作.
代码如下:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
void flatten(TreeNode* root) {
if(!root)return;
flatten(root->left);
TreeNode*temp=root->right;//记录当前节点的右子树
root->right=root->left;//将当前节点的right指向当前节点的left。如果没有上一步的TreeNode*temp=root->right;就会让当前节点原先的右子树节点丢失
root->left=nullptr;
while(root->right){root=root->right;}//这个是一直向后走的,此时的root->right实际上是原先的root->left。即root-、、 //>right=root->left;这一句,这句的意思是找到左子树的最右边节点。
flatten(root->right);//这个放在flatten(root->left);之后或者这儿都是可以的,因为上面的root->right=root->left;所以这个是将上面的
中的2,3,4结构展开。
root->right=temp;//这个是将左子树的最右边节点指向根节点右子树
}
};
class Solution {
public:
void flatten(TreeNode* root) {
if(!root)return;
flatten(root->left);
TreeNode*pre=root->right;
root->right=root->left;
root->left=nullptr;
while(root->right)root=root->right;//
root->right=pre;
flatten(root->right);
}
};
这个是让递归实现了一个一个点的回溯。