题目描述
给定一个二叉树,原地将其展开为一个单链表。传送门

/**
 * 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) {}
 * };
 */

Method1:利用额外空间,不能算是原地转换。

方法:首先通过前序遍历,将各个节点的值存放到数组中,然后遍历数组中存放的节点,将后一个节点作为前一个节点的右侧节点。

class Solution {
public:
    void flatten(TreeNode* root) {
        vector<TreeNode*> arr;
        dfs(root, arr);
        for(int i = 1; i < arr.size(); i++)
        {
            TreeNode *prve = arr[i-1];
            TreeNode *crve = arr[i];
            prve->left = nullptr;
            prve->right = crve;
        }

    }

    void dfs(TreeNode *root, vector<TreeNode*> &arr)
    {
        if(root != nullptr)
        {
            arr.push_back(root);
            dfs(root->left, arr);
            dfs(root->right, arr);
        }
    }
};

Method2:寻找前驱节点

注意到前序遍历访问各节点的顺序是根节点、左子树、右子树。如果一个节点的左子节点为空,则该节点不需要进行展开操作。如果一个节点的左子节点不为空,则该节点的左子树中的最后一个节点被访问之后,该节点的右子节点被访问。该节点的左子树中最后一个被访问的节点是左子树中的最右边的节点,也是该节点的前驱节点。因此,问题转化成寻找当前节点的前驱节点。

具体做法是,对于当前节点,如果其左子节点不为空,则在其左子树中找到最右边的节点,作为前驱节点,将当前节点的右子节点赋给前驱节点的右子节点,然后将当前节点的左子节点赋给当前节点的右子节点,并将当前节点的左子节点设为空。对当前节点处理结束后,继续处理链表中的下一个节点,直到所有节点都处理结束。

class Solution {
public:
    void flatten(TreeNode* root) {
        TreeNode *curr = root;
        while(curr != nullptr)
        {
            if(curr->left != nullptr)
            {
                TreeNode *temp = curr->left;
                TreeNode *next = curr->left;
                while(next->right != nullptr)
                    next = next->right;
                next->right = curr->right;
                curr->left = nullptr;
                curr->right = temp;

            }

            curr = curr->right;
        }
    }
};