关键点在于原地展开,如果不要求原地的话,直接中序遍历再生成链表就可以了。
要原地的话,应该就是用递归了,其实思路很简单,先保存右子树,然后把左子树接到右边,再把右子树接在左子树的最右节点,自上而下递归:
1
/ \
2 5
/ \ \
3 4 6
//左子树插到右子树的位置
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
.
.
.
class Solution {
public:
void flatten(TreeNode* root) {
if(!root) return;
while(root){
if(!root->left){
root = root->right;
continue;
}
auto left = root->left;
while(left->right) left = left->right;//左子树最右节点
left->right = root->right;//右子树接到左子树最右节点
root->right = root->left;//左子树接到右子树位置
root->left = NULL;//左子树置空
root = root->right;
}
}
};
如果用递归来写:
class Solution {
public:
void flatten(TreeNode* root) {
if(!root) return;//递归出口
flatten(root->left);
flatten(root->right);
//现在可以认为左右子树都已经处理好了
auto tmp = root->right;//临时保存右子树
root->right = root->left;//左子树接到右边
root->left = NULL;//左子树置空
//寻找左洗子树的最右节点
while(root->right) root = root->right;
root->right = tmp;.//右子树接到左子树的最右节点
}
};
我们还可以进行后续遍历,自下而上:
可以看这个题解:详细通俗的思路分析,多解法 - 二叉树展开为链表 - 力扣(LeetCode)
class Solution {
public:
//后续遍历
TreeNode *pre = NULL;
void flatten(TreeNode* root) {
if(!root) return;
flatten(root->right);
flatten(root->left);
root->right = pre;
root->left = NULL;//左子树置空
pre = root;
}
};
还可以借助栈来保存右子树,然后结合前序遍历:
class Solution {
public:
void flatten(TreeNode* root) {
if(!root) return;
stack<TreeNode*> stk;
stk.push(root);
TreeNode *pre = NULL;
while(!stk.empty()){
auto tmp = stk.top();
stk.pop();
if(pre){
pre->right = tmp;
pre->left = NULL;
}
if(tmp->right) stk.push(tmp->right);
if(tmp->left) stk.push(tmp->left);
pre = tmp;
}
}
};