Leetcode 剑指 Offer II 052. 递增顺序搜索树

题目难度: 简单

原题链接

今天继续更新 Leetcode 的剑指 Offer(专项突击版)系列, 大家在公众号 算法精选 里回复 剑指offer2 就能看到该系列当前连载的所有文章了, 记得关注哦~

题目描述

给你一棵二叉搜索树,请 按中序遍历 将其重新排列为一棵递增顺序搜索树,使树中最左边的节点成为树的根节点,并且每个节点没有左子节点,只有一个右子节点。

示例 1:

Leetcode 剑指 Offer II 052. 递增顺序搜索树_第1张图片

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

示例 2:

Leetcode 剑指 Offer II 052. 递增顺序搜索树_第2张图片

  • 输入:root = [5,1,7]
  • 输出:[1,null,5,null,7]

提示:

  • 树中节点数的取值范围是 [1, 100]
  • 0 <= Node.val <= 1000

题目思考

  1. 如何降低时间和空间复杂度?

解决方案

思路
  • 根据题目描述, 一个很容易想到的思路就是中序遍历, 然后将遍历到的节点用列表存下来, 最后遍历列表, 并依次将每个节点的右子节点指向列表里的下一个节点, 当然也要把左子节点置为空
  • 不过这样我们就得遍历每个节点两遍, 而且需要额外的列表来存储节点, 有没有更好的方法呢?
  • 回顾二叉搜索树的性质, 其中序遍历的节点本身就是有序的, 所以如果我们保存了前一个节点, 那么在遍历当前节点时, 只需要将前一个节点的右子节点指向它即可, 然后将前一节点更新为当前节点, 以此类推, 这样最终中序遍历完成时, 就得到了题目要求的递增顺序搜索树
  • 当然, 我们在遍历到当前节点时, 也需要将其左子节点置为空, 这里之所以将当前节点而不是前一节点的左子节点置为空, 是因为这样才能保证最终所有节点的左子节点都是空, 否则最后一个节点的左子节点就可能不是空, 会导致出现循环
  • 利用上述做法, 我们就无需引入额外的列表存储, 也不需要再次遍历了
  • 另外在遍历第一个节点时, 由于它没有前一节点, 所以我们可以额外引入一个哨兵节点, 并将最开始的前一节点初始化为哨兵, 这样哨兵的右子节点就是最终形成的树的根, 返回它即可
  • 下面代码中有详细的注释, 方便大家理解
复杂度
  • 时间复杂度 O(N): 每个节点只会被遍历一次
  • 空间复杂度 O(H): 递归调用最多使用 O(H) 栈空间, H 是树的高度
代码
class Solution:
    def increasingBST(self, root: TreeNode) -> TreeNode:
        # 使用哨兵节点, 作为最开始的前一节点
        dummy = TreeNode()
        pre = dummy

        def inorder(node):
            # 中序遍历
            nonlocal pre
            if not node:
                return
            inorder(node.left)
            # 将当前节点的左子节点置为空, 注意不能将pre的左子节点置为空, 否则会漏掉最后一个节点
            node.left = None
            # 将前一节点的右子节点指向当前节点
            pre.right = node
            # 更新前一节点为当前节点
            pre = node
            inorder(node.right)

        inorder(root)
        return dummy.right

大家可以在下面这些地方找到我~

我的 GitHub

我的 Leetcode

我的 CSDN

我的知乎专栏

我的头条号

我的牛客网博客

我的公众号: 算法精选, 欢迎大家扫码关注~

Leetcode 剑指 Offer II 052. 递增顺序搜索树_第3张图片

你可能感兴趣的:(Leetcode,leetcode,算法,职场和发展)