LeetCode 114. Flatten Binary Tree to Linked List

Recursive

一开始我想用preorder加上prev指针来做,但是很快就发现了问题。由于preorder,root先处理,而在本题中,即先将root加到之前的prev之后。假如树是 (1 (2) (3)),dfs到节点2时,prev->right=root 会使得1的右儿子变成2,这会使得节点1的右子树丢失,而且会造成死循环。

PreOrder

备份 root->right,而且 root->left 要在递归左子树之后再置为 null,或者可以left和right都copy一份。

Easy-Understand-Java-Recursive-solution-beat-100-with-Explanation

Java-pre-order-and-post-order-solution-same-idea-with-114.-Flatten-Binary-Tree-to-Linked-List

PostOrder

有一个巧妙避免上述问题的方法是,将preorder的顺序反过来,即 (right, left, root),从后往前构建linked list。这样根最后处理,无论我们怎么修改root的left和right都不会有任何问题,因为左子树和右子树都已经递归完毕了。

之前思路中prev是记录linked list最后一个元素。现在我们反过来之后,我们需要记录linked list第一个元素,记作first。

class Solution {
public:
    TreeNode *first=NULL;
    
    void flatten(TreeNode* root) {
        if (root==NULL) return;
        flatten(root->right);
        flatten(root->left);
        root->right = first;
        root->left = NULL;
        first = root;
    }
};

时间复杂度 O(n)  空间复杂度 O(h)

实际上,上述问题只有preorder会出现,inorder和postorder都是没有问题的。

inorder的例子可以见 LeetCode 426. Convert Binary Search Tree to Sorted Doubly Linked List

 

Iterative

PreOrder Iterative

preorder非递归第一种写法由于stack的存在,左右儿子放到了stack里,因此修改当前节点的左右节点没有影响。

preorder第二种写法就不行了,和递归中的出现的问题一样,利用copy节点的方法可能可以,但是太过繁琐。

class Solution {
public:
    void flatten(TreeNode* root) {
        if (root==NULL) return;
        TreeNode *prev=NULL;
        stack<TreeNode *> s({root});
        while (!s.empty()){
            TreeNode *cur=s.top(); s.pop();
            if (prev!=NULL){
                prev->right = cur;
                prev->left = NULL;
            }
            prev = cur;
            if (cur->right) s.push(cur->right);
            if (cur->left) s.push(cur->left);
        }
    }
};

 

Iterative without Stack

本题也可以直接非递归来做。每次把左子树移到右边,接上右子树。

http://www.cnblogs.com/grandyang/p/4293853.html 里有图,很形象。

class Solution {
public:
    void flatten(TreeNode* root) {
        TreeNode *p=root;
        while (p){
            if (p->left){
                TreeNode *q=p->left;
                while (q->right) q=q->right;
                q->right = p->right;
                p->right = p->left;
                p->left = NULL;
            }
            p = p->right;
        }
    }
};

 

Others

Recursive [Not optimal]

树里的 divide and conquer 感觉和 postorder traversal 就是一个东西,反正都是递归。

下面方法返回了 root ,也可以不返回,直接用 flatten 自己递归也行。

class Solution {
public:
    
    void flatten(TreeNode* root) {  
        helper(root);
    }
    
    TreeNode *helper(TreeNode* root) {  
        if (root==NULL) return NULL;
        TreeNode *left=helper(root->left);
        TreeNode *right=helper(root->right);
        root->left = NULL;
        root->right = left;
        TreeNode *cur=root;
        while (cur->right!=NULL) cur=cur->right;
        cur->right = right;
        return root;
    }
};

 

Reference

https://leetcode.com/problems/flatten-binary-tree-to-linked-list/discuss/36977/My-short-post-order-traversal-Java-solution-for-share

posted @ 2018-08-26 00:05  約束の空  阅读(209)  评论(0编辑  收藏  举报