首页 > 其他分享 >【Leecode】Leecode刷题之路第94天之二叉树的中序遍历

【Leecode】Leecode刷题之路第94天之二叉树的中序遍历

时间:2024-12-29 22:28:27浏览次数:3  
标签:predecessor 遍历 中序 Leecode right 二叉树 root 复杂度

题目出处

94-二叉树的中序遍历-题目出处

题目描述

在这里插入图片描述

个人解法

思路:

todo

代码示例:(Java)

todo

复杂度分析

todo

官方解法

94-二叉树的中序遍历-官方解法

方法1:递归

思路:

在这里插入图片描述

代码示例:(Java)

class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;

    TreeNode() {
    }

    TreeNode(int val) {
        this.val = val;
    }

    TreeNode(int val, TreeNode left, TreeNode right) {
        this.val = val;
        this.left = left;
        this.right = right;
    }
}

public class Solution1 {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<Integer>();
        inorder(root, res);
        return res;
    }

    public void inorder(TreeNode root, List<Integer> res) {
        if (root == null) {
            return;
        }
        inorder(root.left, res);
        res.add(root.val);
        inorder(root.right, res);
    }


}

复杂度分析

  • 时间复杂度:O(n),其中 n 为二叉树节点的个数。二叉树的遍历中每个节点会被访问一次且只会被访问一次。
  • 空间复杂度:O(n)。空间复杂度取决于递归的栈深度,而栈深度在二叉树为一条链的情况下会达到 O(n) 的级别。

方法2:迭代

思路:

方法一的递归函数我们也可以用迭代的方式实现,两种方式是等价的,区别在于递归的时候隐式地维护了一个栈,而我们在迭代的时候需要显式地将这个栈模拟出来,其他都相同,具体实现可以看下面的代码。

在这里插入图片描述

代码示例:(Java)

public class Solution2 {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<Integer>();
        Deque<TreeNode> stk = new LinkedList<TreeNode>();
        while (root != null || !stk.isEmpty()) {
            while (root != null) {
                stk.push(root);
                root = root.left;
            }
            root = stk.pop();
            res.add(root.val);
            root = root.right;
        }
        return res;
    }


}

复杂度分析

  • 时间复杂度:O(n),其中 n 为二叉树节点的个数。二叉树的遍历中每个节点会被访问一次且只会被访问一次。
  • 空间复杂度:O(n)。空间复杂度取决于栈深度,而栈深度在二叉树为一条链的情况下会达到 O(n) 的级别。

方法3:Morris 中序遍历

思路:

Morris 遍历算法是另一种遍历二叉树的方法,它能将非递归的中序遍历空间复杂度降为 O(1)。

Morris 遍历算法整体步骤如下(假设当前遍历到的节点为 x):

1.如果 x 无左孩子,先将 x 的值加入答案数组,再访问 x 的右孩子,即 x=x.right。

2.如果 x 有左孩子,则找到 x 左子树上最右的节点(即左子树中序遍历的最后一个节点,x 在中序遍历中的前驱节点),我们记为 predecessor。根据 predecessor 的右孩子是否为空,进行如下操作。

  • 如果 predecessor 的右孩子为空,则将其右孩子指向 x,然后访问 x 的左孩子,即 x=x.left。
  • 如果 predecessor 的右孩子不为空,则此时其右孩子指向 x,说明我们已经遍历完 x 的左子树,我们将 predecessor 的右孩子置空,将 x 的值加入答案数组,然后访问 x 的右孩子,即 x=x.right。

3.重复上述操作,直至访问完整棵树。

在这里插入图片描述

其实整个过程我们就多做一步:假设当前遍历到的节点为 x,将 x 的左子树中最右边的节点的右孩子指向 x,这样在左子树遍历完成后我们通过这个指向走回了 x,且能通过这个指向知晓我们已经遍历完成了左子树,而不用再通过栈来维护,省去了栈的空间复杂度。

代码示例:(Java)

public class Solution3 {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<Integer>();
        TreeNode predecessor = null;

        while (root != null) {
            if (root.left != null) {
                // predecessor 节点就是当前 root 节点向左走一步,然后一直向右走至无法走为止
                predecessor = root.left;
                while (predecessor.right != null && predecessor.right != root) {
                    predecessor = predecessor.right;
                }

                // 让 predecessor 的右指针指向 root,继续遍历左子树
                if (predecessor.right == null) {
                    predecessor.right = root;
                    root = root.left;
                }
                // 说明左子树已经访问完了,我们需要断开链接
                else {
                    res.add(root.val);
                    predecessor.right = null;
                    root = root.right;
                }
            }
            // 如果没有左孩子,则直接访问右孩子
            else {
                res.add(root.val);
                root = root.right;
            }
        }
        return res;
    }


}

复杂度分析

  • 时间复杂度:O(n),其中 n 为二叉树的节点个数。Morris 遍历中每个节点会被访问两次,因此总时间复杂度为 O(2n)=O(n)。
  • 空间复杂度:O(1)。

考察知识点

1.二叉树

在这里插入图片描述

2.中序遍历

在这里插入图片描述

3.如何创建一个空二叉树

收获

Gitee源码位置

94-二叉树的中序遍历-源码

标签:predecessor,遍历,中序,Leecode,right,二叉树,root,复杂度
From: https://blog.csdn.net/Prince140678/article/details/144792647

相关文章

  • LeetCode110平衡二叉树
    原理本题判断一个二叉树是否为平衡二叉树,核心思路是基于平衡二叉树的定义,即任意节点的左右子树的高度差的绝对值不超过1。通过递归地计算每个节点为根的子树的高度,在计算过程中判断是否满足高度差条件,如果发现某个节点的左右子树高度差超过1,则整棵树不是平衡二叉树,标记为特......
  • 最早发明的自平衡二叉树:AVL
    前言更好的阅读体验默认读者会基本的BST操作。节点定义平衡因子:BF(BalanceFactor),左子树高\(-\)右子树高。平衡树是让树的形态尽可能像完全二叉树,而不是链。在AVL中,我们认为\(\left|\text{BF}\right|\le1\),也就是BF为\(0,1,-1\)时的子树是平衡的,否则就是不平衡......
  • 【数据结构】二叉树
    二叉树1.树型结构(了解)1.1概念1.2概念(重要)1.3树的表示形式(了解)1.4树的应用2.二叉树(重点)2.1概念2.2两种特殊的二叉树2.3二叉树的性质2.4二叉树的存储2.5二叉树的基本操作2.5.1前置说明2.5.2二叉树的遍历2.5.3二叉树的基本操作2.6二叉树相关oj题【本节......
  • 二叉树中的最大路径和(递归)
    二叉树中的 路径 被定义为一条节点序列,序列中每对相邻节点之间都存在一条边。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点,且不一定经过根节点。路径和 是路径中各节点值的总和。给你一个二叉树的根节点 root ,返回其 最大路径和 。 示例......
  • 头歌实训数据结构与算法-二叉树及其应用(第7关:由前序和中序遍历序列构造二叉树)
    任务描述本关任务要求采用前序遍历序列和中序遍历序列构造二叉树。相关知识给定一棵二叉树的前序遍历序列和中序遍历序列可以构造出这棵二叉树。例如前序序列是ABDECFG,中序序列是DBEAFCG,那么这颗二叉树的结构如图1所示。树结点结构定义为:structBTNode{    c......
  • 深入探索哈夫曼编码与二叉树的遍历
    编码表(将字符转换成二进制01数字)定长的编码方式不定长的编码方式压缩率很高,但是会产生数据歧义哈夫曼编码出现的次数越多,权重分配的值越小。哈夫曼树,左1右0,转换成编码哈夫曼编码(压缩率高,数据不会产生歧义)哈夫曼编码----->二叉......
  • 106.从中序与后序遍历构造二叉树
    106.从中序与后序遍历构造二叉树中序:左根右后序:左右根思路:中序遍历需要定位根节点的坐标前序和后序需要定位子树根节点的坐标1.构造map方便通过root->value拿到该值在中序中的下标(in_root)2.从后序的最后一个值拿到当前root的value3.通过map拿到in_root4.构造此时结......
  • 【257. 二叉树的所有路径 简单】
    题目:给你一个二叉树的根节点root,按任意顺序,返回所有从根节点到叶子节点的路径。叶子节点是指没有子节点的节点。示例1:输入:root=[1,2,3,null,5]输出:[“1->2->5”,“1->3”]示例2:输入:root=[1]输出:[“1”]提示:树中节点的数目在范围[1,100]内-100<=N......
  • 代码随想录——贪心23监控二叉树
    思路这道题目首先要想,如何放置,才能让摄像头最小的呢?从题目中示例,其实可以得到启发,我们发现题目示例中的摄像头都没有放在叶子节点上!这是很重要的一个线索,摄像头可以覆盖上中下三层,如果把摄像头放在叶子节点上,就浪费的一层的覆盖。所以把摄像头放在叶子节点的父节点位置,才......
  • 二叉树和哈希表
    二叉树二叉树是每个节点最多有两个子树的树结构,通常子树被称作“左子树”和“右子树”。二叉树的递归定义为:二叉树或者是一棵空树,或者是一棵由一个根节点和两棵互不相交的分别称作根的左子树和右子树所组成的非空树,左子树和右子树又同样都是二叉树。下面相关代码实现都利用了......