要求:按前序拆成链表
思路:
错误示范:访问2左二子3时已经把2右儿子4改成3了,4丢了
class Solution {
public:
TreeNode* pre;
void preorder(TreeNode* root){
pre->right=root;//可能还会回到pre右儿子这里不能改
pre=root;
if(root->left)preorder(root->left);
if(root->right)preorder(root->right);
root->left=nullptr;
}
void flatten(TreeNode* root) {
if(!root)return;
TreeNode* head=new TreeNode(-1);
pre=head;
preorder(root);
}
};
正确示范,既然丢了就先存起来。最后rootleft可以换成在pre处就改了
class Solution {
public:
TreeNode* pre;
void preorder(TreeNode* root){
pre->right=root;
pre=root;
TreeNode* l=root->left;
TreeNode* r=root->right;
if(l)preorder(l);
if(r)preorder(r);
root->left=nullptr;
}
void flatten(TreeNode* root) {
if(!root)return;
TreeNode* head=new TreeNode(-1);
pre=head;
preorder(root);
}
};
法二:倒过来遍历不用考虑丢失的问题
class Solution {
public:
TreeNode* pre=nullptr;
void rpreorder(TreeNode* root){
if(root->right)rpreorder(root->right);
if(root->left)rpreorder(root->left);
root->left=nullptr;
root->right=pre;
pre=root;
}
void flatten(TreeNode* root) {
if(!root)return;
rpreorder(root);
}
};
法三:先序遍历迭代写法是先入栈所有左节点,然后弹出一个换右节点,循环。另一种写法是类似层序,右孩子比左孩子入栈
class Solution {
public:
void flatten(TreeNode* root) {
if(!root)return;
stack<TreeNode*> s;
TreeNode* pre=nullptr;
s.push(root);
while(!s.empty()){
TreeNode* tmp=s.top();
s.pop();
if(pre){
pre->right=tmp;
pre->left=nullptr;
}
pre=tmp;
if(tmp->right)s.push(tmp->right);
if(tmp->left)s.push(tmp->left);
}
}
};
法四:想象。
class Solution {
public:
void flatten(TreeNode* root) {
while (root != nullptr) {
if (root->left != nullptr) {
auto most_right = root->left; // 如果左子树不为空, 那么就先找到左子树的最右节点
while (most_right->right != nullptr) most_right = most_right->right; // 找最右节点
most_right->right = root->right; // 然后将跟的右孩子放到最右节点的右子树上
root->right = root->left; // 这时候跟的右孩子可以释放, 因此我令左孩子放到右孩子上
root->left = nullptr; // 将左孩子置为空
}
root = root->right; // 继续下一个节点
}
return;
}
};