LeetCode题目(Python实现): 恢复二叉搜索树

题目

二叉搜索树中的两个节点被错误地交换。

请在不改变其结构的情况下,恢复这棵树。

示例1 :

输入: [1,3,null,null,2]

   1
  /
 3
  \
   2

输出: [3,1,null,null,2]

   3
  /
 1
  \
   2

示例2 :

输入: [3,1,4,null,null,2]

  3
 / \
1   4
   /
  2

输出: [2,1,4,null,null,3]

  2
 / \
1   4
   /
  3

进阶:

  • 使用 O(n) 空间复杂度的解法很容易实现。
  • 你能想出一个只使用常数空间的解决方案吗?

对数组进行排序

算法实现

def recoverTree(self, root: TreeNode) -> None:
    def inorder(r: TreeNode) -> List[int]:
        return inorder(r.left) + [r.val] + inorder(r.right) if r else []

    def find_two_swapped(nums: List[int]) -> (int, int):
        n = len(nums)
        x = y = -1
        for i in range(n - 1):
            if nums[i + 1] < nums[i]:
                y = nums[i + 1]
                # first swap occurence
                if x == -1:
                    x = nums[i]
                # second swap occurence
                else:
                    break
        return x, y

    def recover(r: TreeNode, count: int):
        if r:
            if r.val == x or r.val == y:
                r.val = y if r.val == x else x
                count -= 1
                if count == 0:
                    return
            recover(r.left, count)
            recover(r.right, count)

    nums = inorder(root)
    x, y = find_two_swapped(nums)
    recover(root, 2)

执行结果

执行结果 : 通过
执行用时 : 116 ms, 在所有 Python3 提交中击败了13.87%的用户
内存消耗 : 13.7 MB, 在所有 Python3 提交中击败了6.12%的用户
在这里插入图片描述

复杂度分析

  • 时间复杂度:O(n)

  • 空间复杂度:O(n)

迭代中序遍历

算法实现

def recoverTree(self, root: TreeNode) -> None:
    stack = []
    x = y = pred = None

    while stack or root:
        while root:
            stack.append(root)
            root = root.left
        root = stack.pop()
        if pred and root.val < pred.val:
            y = root
            if not x:
                x = pred
            else:
                break
        pred = root
        root = root.right

    x.val, y.val = y.val, x.val

执行结果

在这里插入图片描述

复杂度分析

  • 时间复杂度:O(n)

  • 空间复杂度:O(H),其中 H 指的是树的高度。

递归中序遍历

算法实现

def recoverTree(self, root: TreeNode) -> None:
	def find_two_swapped(root: TreeNode):
	    nonlocal x, y, pred
	    if root is None:
	        return
	
	    find_two_swapped(root.left)
	    if pred and root.val < pred.val:
	        y = root
	        # first swap occurence
	        if x is None:
	            x = pred
	            # second swap occurence
	        else:
	            return
	    pred = root
	    find_two_swapped(root.right)
	
	x = y = pred = None
	find_two_swapped(root)
	x.val, y.val = y.val, x.val

执行结果

在这里插入图片描述

复杂度分析

  • 时间复杂度:O(n)

  • 空间复杂度:O(H),其中 H 指的是树的高度。

Morris 中序遍历

算法实现

def recoverTree(self, root: TreeNode) -> None:
	# predecessor is a Morris predecessor.
    # In the 'loop' cases it could be equal to the node itself predecessor == root.
    # pred is a 'true' predecessor,
    # the previous node in the inorder traversal.
    x = y = predecessor = pred = None

    while root:
        # If there is a left child
        # then compute the predecessor.
        # If there is no link predecessor.right = root --> set it.
        # If there is a link predecessor.right = root --> break it.
        if root.left:
            # Predecessor node is one step left
            # and then right till you can.
            predecessor = root.left
            while predecessor.right and predecessor.right != root:
                predecessor = predecessor.right

            # set link predecessor.right = root
            # and go to explore left subtree
            if predecessor.right is None:
                predecessor.right = root
                root = root.left
            # break link predecessor.right = root
            # link is broken : time to change subtree and go right
            else:
                # check for the swapped nodes
                if pred and root.val < pred.val:
                    y = root
                    if x is None:
                        x = pred
                pred = root

                predecessor.right = None
                root = root.right
        # If there is no left child
        # then just go right.
        else:
            # check for the swapped nodes
            if pred and root.val < pred.val:
                y = root
                if x is None:
                    x = pred
            pred = root
            root = root.right

    x.val, y.val = y.val, x.val

执行结果

在这里插入图片描述

复杂度分析

  • 时间复杂度:O(n)

  • 空间复杂度:O(1)

小结

题解思路写的很清楚,但是刚开始自己没有写出来,完全没有想法,可能是被困难题目吓到了,看了题解将困难题目分成三个简单的子问题,先用暴力解出,再对前两步进行优化整合,得到实现中序遍历的不同方法。

主要还是对二叉树的特性不太熟悉,没想到中序遍历是一个升序序列。但首要问题是应该对题目进行分拆,把难题分成一步一步简单的问题,至少要写出暴力的解。想起之前自己总结的解题方法。。。自己却被困难吓到了,忘了步骤,反而想一步解出=。=

以后一定要注重对困难题的分拆!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值