Leetcode 笔记 99 - Recover Binary Search Tree

本文介绍了一种在不改变二叉搜索树结构的情况下,通过中序遍历找到并交换两个错误位置节点的方法,实现了二叉搜索树的修复。提供了一种使用O(n)空间的直接解决方案,并介绍了更高级的常数空间复杂度算法——Morris二叉树遍历算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:Recover Binary Search Tree | LeetCode OJ

Two elements of a binary search tree (BST) are swapped by mistake.

Recover the tree without changing its structure.

Note: A solution using O(n) space is pretty straight forward. Could you devise a constant space solution?

Tags: Tree, Depth-first Search

分析

这道题的基本要求是使用O(n)的空间,进阶要求是使用常数空间。O(n)的算法比较直接,直接从二叉查找树的用途就能推出。二叉查找树的特点是中序遍历后能够生成递增的序列,因此只需要对给定的二叉查找树进行中序遍历,遍历过程中找到非递增情况,就能够得出不符合递增规律的两个数,交换后二叉查找树的恢复就完成了。

在设计使用常数空间的算法时,一种思路是在中序遍历中传递上一个遍历到的值,这样就在遍历过程中完成了比对,而不需额外的空间存储遍历结果,但这种算法本质也是O(n)的,因为普通的深度优先遍历中用到的递归,本质上是想中间结果压入栈内,因此还是需要O(n)的空间复杂度。

真正O(n)空间复杂度的算法需要用时间换空间,常用的算法是Morris二叉树遍历算法。

示例

class Solution:
  _previous = None
  _swapA = _swapB = None

  # @param root, a tree node
  # @return a tree node
  def recoverTree(self, root):
    self._coverTree(root)

    if self._swapA is not None and self._swapB is not None:
      temp = self._swapA.val
      self._swapA.val = self._swapB.val
      self._swapB.val = temp
    return root

  def _coverTree(self, root):
    if root is None or root.val is None:
      return

    self._coverTree(root.left)
    if self._previous is not None and self._previous.val is not None:
      if self._previous.val > root.val:
        if self._swapA is None:
          self._swapA = self._previous
        self._swapB = root

    self._previous = root
    self._coverTree(root.right)

Leetcode 笔记系列的Python代码共享在https://github.com/wizcabbit/leetcode.solution

示例说明

  • 使用中序遍历时,最直接的想法是中序遍历,同时将遍历结果储存在一个数组中。中序遍历结束后,再行遍历这个数组查找非递增的值。其实还可以在中序遍历过程中每次传入上一个结点的值,一边遍历一边比对是否递增。当然这种方法的实际空间复杂度没有变化,因为递归过程中的每次中间结果都会被压栈,实际仍然使用了和单独数组同样的空间

相关题目

Validate Binary Search Tree

转载于:https://www.cnblogs.com/wizcabbit/p/leetcode-99-recover-binary-search-tree.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值