114. Flatten Binary Tree to Linked List

Flatten Binary Tree to Linked List

题目

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

解析

很容易看到展开的tree是一个前序遍历的序列。基于这个想法我们可以
思路一:

  1. 前序遍历一次,并把结点保存起来;
  2. 针对保存的结点重新序列化;

这样时间复杂度为O(n),空间复杂度为O(n).

空间复杂度有点高,这时我发现如果能够使得叶子节点的right指向其后继的话,这样就很容易展成题目要求的形式了。
那么思路二:

  1. 使用前序遍历方法线索化二叉树,线索的对象为终端节点。
  2. 展开

思路二代码

void flatten(struct TreeNode* root) {
    //前序叶子结点线索化
    struct TreeNode throot;
    struct TreeNode*pre=&throot;
    struct TreeNode* p =root;
    struct TreeNode*stack[50]={0};
    int stacklen=0;
    while(p||stacklen>0){
        if(p){
            if(pre->left==NULL&&pre->right == NULL){
                pre->right = p;
            }
            pre = p;
            stack[stacklen++]=p;
            p=p->left;
        }
        else{
            p=stack[--stacklen];
            p=p->right;
        }
    }
    //展开
    p=root;
    while(p){
        if(p->left){
            p->right=p->left;
            p->left=NULL;
        }
        p=p->right;
    }
}

代码分析
每个节点访问了两次,即2n,则时间复杂度为O(n).
空间复杂度依赖树的深度,树的深度为log2(n)~n。那么空间复杂度也是O(n).
对比思路一貌似一点优势也没有。哭了~~~~

高效方法

思路三:
1. 先让当前节点的右儿子指向左儿子,左儿子的“最右下”(即以左儿子为root前序遍历的最后一个结点)指向当前节点的原来的右儿子
2. 依次迭代即可。

思路三代码

void flatten(struct TreeNode* root) {
    //链表的插入法
    if(root==NULL) return;
    struct TreeNode* p,*q,*s;
    p=root;
    q=NULL;
    s=NULL;
    while(p){
        s=p->left;
        if(s!=NULL){
            q=p->right;
            //寻找最右下结点
            while(s->left||s->right){
                if(s->right){
                    s= s->right;
                }
                else{
                    s=s->left;
                }
            }
            s->right=q;
            p->right=p->left;
            p->left=NULL;
        }
        p=p->right;
    }
}

思路4点击查看

代码

void flatten(struct TreeNode* root) {
    //链表的插入法
    if(root==NULL) return;
    struct TreeNode* cur,*pre;
    cur=root;
    while(cur){
        if(cur->left!=NULL){
            pre=cur->left;
            while(pre->right){
                pre=pre->right;
            }
            pre->right=cur->right;
            cur->right=cur->left;
            cur->left=NULL;
        }
        cur=cur->right;       
    }
}

思路4 vs 思路3

     1
    / \
   2   6
  / \   \
 3   4   7
    /
   5    

思路三 一步操作之后:

   1
    \
     2
    / \ 
   3   4
      /
     5
      \
       6
        \
         7 

思路四 一步操作之后:

   1
    \
     2
    / \ 
   3   4
      / \
     5   6
          \
           7

可以看出,思路四不仅代码简单,效率也比思路三高很多。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值