重点:
(1)前序遍历:存储前序遍历序列,然后建立新链表;迭代和递归两种实现;
(2)寻找前驱节点:空间复杂度O(1)。
难度中等
给你二叉树的根结点 root
,请你将它展开为一个单链表:
- 展开后的单链表应该同样使用
TreeNode
,其中right
子指针指向链表中下一个结点,而左子指针始终为null
。 - 展开后的单链表应该与二叉树 先序遍历 顺序相同。
示例 1:
输入:root = [1,2,5,3,4,null,6] 输出:[1,null,2,null,3,null,4,null,5,null,6]
示例 2:
输入:root = [] 输出:[]
示例 3:
输入:root = [0] 输出:[0]
提示:
- 树中结点数在范围
[0, 2000]
内 -100 <= Node.val <= 100
进阶:你可以使用原地算法(O(1)
额外空间)展开这棵树吗?
解析:
方法1:前序遍历
前序遍历之后,把节点顺序存储下来,然后建立链表即可。左指针指向nullptr,右指针指向下一个元素;
方法2:寻找前驱节点
对于一个节点,如果其没有左子树,只有右子树,那么该节点就不需要展开操作。如果其有左子树,那么对于其右子树来说,左子树的最后一个节点被访问之后,该节点的右子树也即将被访问。这说明左子树的最后一个节点是右子树的前驱节点,也是该节点的前驱节点(因为是先序遍历)。那么问题转化为寻找前驱节点。
对于一个左子树非空的节点Anode,我们寻找其左子树C最后一个节点,就寻找其最右边的节点B。找到之后,将A的右子树连接到B的右子树Bnode->right=C,然后将左子树C连接到A的右子树Anode->right=C,然后Anode->left=nullptr。此时节点A只有右子树。那么寻找其右子树的第一个节点,进行再次操作。
代码:
class Solution {
public:
void flatten(TreeNode* root) {
vector<TreeNode*> vec;
stack<TreeNode*> stk;
while(!stk.empty()||root!=nullptr){
while(root!=nullptr){
stk.push(root);
vec.push_back(root);
root=root->left;
}
root=stk.top();
stk.pop();
root=root->right;
}
int size=vec.size();
for(int i=1;i<size;i++){
TreeNode *pre=vec.at(i-1),*cur=vec.at(i);
pre->left=nullptr;
pre->right=cur;
}
}
};
class Solution {
public:
void flatten(TreeNode* root) {
TreeNode *cur=root;
while(cur!=nullptr){
if(cur->left!=nullptr){
auto next=cur->left;//即将链接到cur的右子树
auto pressdor=next;
while(pressdor->right!=nullptr)
pressdor=pressdor->right;
pressdor->right=cur->right;
cur->left=nullptr;
cur->right=next;
}
cur=cur->right;
}
}
};