力扣第114题-二叉树展开为链表

116 阅读2分钟

Offer 驾到,掘友接招!我正在参与2022春招系列活动-刷题打卡任务,点击查看活动详情

前言

力扣第114题 二叉树展开为链表 如下所示:

给你二叉树的根结点 root ,请你将它展开为一个单链表:

  • 展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null 。
  • 展开后的单链表应该与二叉树 先序遍历 顺序相同。

示例 1:

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

一、思路

先分析一下题目,题目的意思很简单:将树按照先序遍历转为链表。链表的元素由树节点 TreeNode 组成,每个 TreeNode 节点的左孩子都为 null

实现的步骤主要分为以下两个步骤:

  1. 使用 先序遍历 得到二叉树的排列顺序
  2. 再根据排列顺序,组成新的链表

但是为了效率考虑,我们可以在遍历各个节点的时候就生成一个新的链表(这并不是原地交换)。最后再将新链表赋值给原来的链表即可。

举个例子

此处以示例一中的 root = [1,2,5,3,4,null,6] 作为例子

  1. 先使用递归可以得到该二叉树的前序遍历结果 1 -> 2 -> 3 -> 4 -> 5 -> 6,此时这个结果存储在一个新的二叉树中
  2. 然后我们将原根节点 root 指向遍历的结果即可
  3. 最终可以得到由 TreeNode 组成的链表如下图所示:

image.png

二、实现

实现代码

实现方式与思路中保持一致。不足的地方就是需要使用额外的空间来存储前序遍历的结果。

    TreeNode ret = new TreeNode();
    TreeNode head = ret;

    public void flatten(TreeNode root) {
        preDfs(root);
        if (ret.right != null){
            root.left = null;
            root.right = ret.right.right;
        }
    }

    /**
     * 获得树前序便利的结果
     */
    private void preDfs(TreeNode root){
        if (root == null)
            return;
        head.right = new TreeNode(root.val);
        head = head.right;
        // 前序遍历:根左右
        preDfs(root.left);
        preDfs(root.right);
    }

测试代码

    public static void main(String[] args) {
        TreeNode treeNode = new TreeNode(1,
                new TreeNode(2, new TreeNode(3), new TreeNode(4)),
                new TreeNode(5, null, new TreeNode(6)));
        new Number114().flatten(treeNode);
        System.out.println(treeNode);
    }

结果

image.png

三、总结

我后面自己去看了以下官方的题解,发现官方题解三中的原地交换的方式真的是非常新颖。我觉得思路中最重要的就是:在遍历左孩子的时候,左孩子最右边的节点就是右孩子的前序节点。这种方式就是 Morris 中序遍历,可以有效的将空间复杂度降为 O(1)

感谢看到最后,非常荣幸能够帮助到你~♥

如果你觉得我写的还不错的话,不妨给我点个赞吧!如有疑问,也可评论区见~