LeetCode 114. Flatten Binary Tree to Linked List

1. 题目描述

Given a binary tree, flatten it to a linked list in-place.

For example,
Given

     1
    / \
   2   5
  / \   \
 3   4   6

The flattened tree should look like:
1
\
2
\
3
\
4
\
5
\
6
click to show hints.

Hints:
If you notice carefully in the flattened tree, each node’s right child points to the next node of a pre-order traversal.

2. 解题思路

拿到这道题目, 我们的基本思路就是使用递归求解, 先将他的左子树变成一个单链表, 再将他的右子树也变成一个单链表, 然后将他们与root 节点整合到一起, 合成一个大的单链表。只需要注意一下, 代码中左右子树为空的情况的特殊处理

3. code

class Solution {
public:
    pair<TreeNode *, TreeNode *> convert(TreeNode * root){
        pair<TreeNode *, TreeNode *> left = make_pair(nullptr, nullptr);
        pair<TreeNode *, TreeNode *> right = make_pair(nullptr, nullptr);
        pair<TreeNode *, TreeNode *> res = make_pair(root, root);
        if (root->left)
            left = convert(root->left);
        if (root->right)
            right = convert(root->right);
        if (left.first && right.first){
            left.second->right = right.first;
            root->right = left.first;
            root->left = nullptr;
            res.second = right.second;
        }
        else if (left.first){
            root->right = left.first;
            root->left = nullptr;
            res.second = left.second;
        }
        else if (right.first){
            root->right = right.first;
            root->left = nullptr;
            res.second = right.second;
        }

        return res;
    }

    void flatten(TreeNode* root) {
        if (root == nullptr)
            return;

        convert(root);
    }
};

4. 大神解法

4.1 post order traversal

post order traversal 或者说是 reversing preorder, 他借助一个辅助节点 prev, prev 表征已经合成的单链表的头节点, 那么, 在处理当前节点的时候, 只需要把他连接到root 节点的right 部分就可以了, 然后同时更新 prev, 最终处理完毕, 就是一个单链表了, 非常 cool 的解法

private TreeNode prev = null;

public void flatten(TreeNode root) {
    if (root == null)
        return;
    flatten(root.right);
    flatten(root.left);
    root.right = prev;
    root.left = null;
    prev = root;
}

4.2 NON-recursive solution

这个解法的思路在于, 他先找到左子树的最后一个节点, 将右子树与他连接起来, 更新root节点, 然后迭代处理 root->right, 简单来说, 他就是每次处理一个根节点, 将处理完毕的根节点就是在最终链表中的位置了。

4.2.1 demo1

class Solution {
public:
    void flatten(TreeNode *root) {
        TreeNode*now = root;
        while (now)
        {
            if(now->left)
            {
                //Find current node's prenode that links to current node's right subtree
                TreeNode* pre = now->left;
                while(pre->right)
                {
                    pre = pre->right;
                }
                pre->right = now->right;
                //Use current node's left subtree to replace its right subtree(original right 
                //subtree is already linked by current node's prenode
                now->right = now->left;
                now->left = NULL;
            }
            now = now->right;
        }
    }
};

4.2.2 demo2

void flatten(TreeNode *root) {
    while (root) {
        if (root->left && root->right) {
            TreeNode* t = root->left;
            while (t->right)
                t = t->right;
            t->right = root->right;
        }

        if(root->left)
            root->right = root->left;
        root->left = NULL;
        root = root->right;
    }
}

4.3 recursive

下面两种方法, 和我们的思路差不多, 不过这里选择迭代方式找到左子树的最右节点, 然后连接右子树

/*This solution is based on recursion. We simply flatten left and right subtree and paste each sublist to the right child of the root. (don't forget to set left child to null)*/
public void flatten(TreeNode root) {
        if (root == null) return;

        TreeNode left = root.left;
        TreeNode right = root.right;

        root.left = null;

        flatten(left);
        flatten(right);

        root.right = left;
        TreeNode cur = root;
        while (cur.right != null) cur = cur.right;
        cur.right = right;
    }
void flatten(TreeNode* root) {
    if (!root) return;
    flatten(root->left);
    flatten(root->right);
    TreeNode *tmp = root->right;
    root->right = root->left;
    root->left = nullptr;
    while (root->right)
        root = root->right;
    root->right = tmp;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值