链表扁平化类题目:从《lc114. 二叉树展开为链表》到《lc-LCR 155二叉搜索树转化为排序的双向链表》

1 lc114. 二叉树展开为链表

1.1 描述

进阶:你可以使用原地算法(O(1) 额外空间)展开这棵树吗?
在这里插入图片描述

1.2 解法一:

先序遍历这棵树并且将节点加入到一个list中,随后按顺序将list中的每一个元素的left指针置换为空,right指针指向下一个节点

1.3 解法二:

按照先序遍历的倒叙方式遍历这棵二叉树,然后同时操作这个节点的左右指针。

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

1.3.1 为什么不能采用先序遍历,然后在过程中将左右指针进行相应的链接和置空呢?

答:因为先根遍历时进行正向的链接,会导致右子树断开,后续就无法遍历右子树中的节点

1.3.2 为什么先序的倒叙是代码中这样写的呢

答:先序遍历是"根-左-右",那么先序的倒叙应该是"右-左-根"

1.3.3 为什么先序的倒叙可以避免右子树的撕裂?

答:其实右子树无论如何都会被断开一次,但是因为右子树中的节点都已经被正确处理完后才开始重新接上,后续就不需要遍历右子树了。

1.3.4 如果让展开后的单链表应该同样使用 TreeNode ,其中 left 子指针指向链表中下一个结点,而right 子指针始终为 null ,解法是不是基本相同?

答:对,遍历结构还是先序的倒叙遍历

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

1.4 方法二:正序

  public void flatten(TreeNode root) {
        if(root==null){
            return;
        }
        while(root!=null){
            TreeNode left=root.left;
            TreeNode right=root.right;
            if(left!=null){
                root.right=left;
                TreeNode pre=left;
                while(pre.right!=null){
                    pre=pre.right;
                }
                pre.right=right;
                //因为都是用右指针衔接的,所以需要打
                root.left=null;
            }

            root=root.right;
        }
        
    }

2 LCR 155二叉搜索树转化为排序的双向链表

多种方法解决leetcode经典题目-LCR 155. 将二叉搜索树转化为排序的双向链表, 同时弄透引用变更带来的bug

3 430. 扁平化多级双向链表

   public Node flatten(Node head) {
        if(head==null)return head;
        Deque<Node>st=new LinkedList<>();
        Node cur=head;
        while(cur!=null){
            Node next=cur.next;
            Node child=cur.child;
            if(child!=null){
                //next指针不空才能加入到队列中,是为了防止corner case:[1,null,2,null,3,null],这种情况下每层链表都只有一个节点
                if(next!=null)
                    st.offerLast(next);//放入栈中
                cur.next=child;
                cur.child=null;
                child.prev=cur;
            }else{
                if(cur.next==null){
                    if(!st.isEmpty()){
                        Node tmp=st.pollLast();
                        cur.next=tmp;
                        tmp.prev=cur;
                    }
                }
            }
            cur=cur.next;
        }
        return head;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值