【数据结构与算法】之深入解析“二叉树展开为链表”的求解思路与算法示例

举报
Serendipity·y 发表于 2022/02/19 00:07:23 2022/02/19
【摘要】 一、题目要求 给你二叉树的根结点 root ,请你将它展开为一个单链表: 展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null;...

一、题目要求

  • 给你二叉树的根结点 root ,请你将它展开为一个单链表:
    • 展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null;
    • 展开后的单链表应该与二叉树先序遍历顺序相同。
  • 示例 1:

在这里插入图片描述

输入:root = [1,2,5,3,4,null,6]
输出:[1,null,2,null,3,null,4,null,5,null,6]

  
 
  • 1
  • 2
  • 示例 2:
输入:root = []
输出:[]

  
 
  • 1
  • 2
  • 示例 3:
输入:root = [0]
输出:[0]

  
 
  • 1
  • 2
  • 提示:
    • 树中结点数在范围 [0, 2000] 内;
    • -100 <= Node.val <= 100。

二、求解算法

① 先序遍历

  • 将左子树插入到右子树的地方;
  • 将原来的右子树接到左子树的最右边节点;
  • 考虑新的右子树的根节点,一直重复上边的过程,直到新的右子树为 null。

在这里插入图片描述

  • 将 1 的左子树插入到右子树的地方:

在这里插入图片描述

  • 将原来的右子树接到左子树的最右边节点:

在这里插入图片描述

  • 将 2 的左子树插入到右子树的地方:

在这里插入图片描述

  • 将原来的右子树接到左子树的最右边节点:

在这里插入图片描述

  • Java 示例:
public void flatten(TreeNode root) {
    while (root != null) { 
        // 左子树为 null,直接考虑下一个节点
        if (root.left == null) {
            root = root.right;
        } else {
            // 找左子树最右边的节点
            TreeNode pre = root.left;
            while (pre.right != null) {
                pre = pre.right;
            } 
            // 将原来的右子树接到左子树的最右边节点
            pre.right = root.right;
            // 将左子树插入到右子树的地方
            root.right = root.left;
            root.left = null;
            // 考虑下一个节点
            root = root.right;
        }
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

② 递归

  • 题目其实就是将二叉树通过右指针,组成一个链表:
1 -> 2 -> 3 -> 4 -> 5 -> 6

  
 
  • 1
  • 我们知道给定的遍历顺序其实就是先序遍历的顺序,所以能不能利用先序遍历的代码,每遍历一个节点,就将上一个节点的右指针更新为当前节点。
  • 先序遍历的顺序是 1 2 3 4 5 6;
  • 遍历到 2,把 1 的右指针指向 2:1 -> 2 3 4 5 6;
    • 遍历到 3,把 2 的右指针指向 3:1 -> 2 -> 3 4 5 6。
  • … …
  • 一直进行下去似乎就解决了这个问题。但现实是残酷的,原因就是把 1 的右指针指向 2,那么 1 的原本的右孩子就丢失了,也就是 5 就找不到了。
  • 解决方法的话,可以逆过来进行:
    • 依次遍历 6 5 4 3 2 1,然后每遍历一个节点就将当前节点的右指针更新为上一个节点;
    • 遍历到 5,把 5 的右指针指向 6:6 <- 5 4 3 2 1;
    • 遍历到 4,把 4 的右指针指向 5:6 <- 5 <- 4 3 2 1。
  • … …
  • 这样就不会有丢失孩子的问题了,因为更新当前的右指针的时候,当前节点的右孩子已经访问过了。而 6 5 4 3 2 1 的遍历顺序其实变形的后序遍历,遍历顺序是右子树->左子树->根节点。
  • Java 示例:
public void flatten(TreeNode root) { 
    Stack<TreeNode> toVisit = new Stack<>();
    TreeNode cur = root;
    TreeNode pre = null;

    while (cur != null || !toVisit.isEmpty()) {
        while (cur != null) {
            toVisit.push(cur); // 添加根节点
            cur = cur.right; // 递归添加右节点
        }
        cur = toVisit.peek(); // 已经访问到最右的节点了
        // 在不存在左节点或者右节点已经访问过的情况下,访问根节点
        if (cur.left == null || cur.left == pre) {
            toVisit.pop(); 
            /**************修改的地方***************/
            cur.right = pre;
            cur.left = null;
            /*************************************/
            pre = cur;
            cur = null;
        } else {
            cur = cur.left; // 左节点还没有访问过就先访问左节点
        }
    } 
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

文章来源: blog.csdn.net,作者:Serendipity·y,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/Forever_wj/article/details/122989772

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。