给你二叉搜索树的根节点 root ,该树中的两个节点被错误地交换。请在不改变其结构的情况下,恢复这棵树。
进阶:使用 O(n) 空间复杂度的解法很容易实现。你能想出一个只使用常数空间的解决方案吗?
示例 1:
输入:root = [1,3,null,null,2]
输出:[3,1,null,null,2]
解释:3 不能是 1 左孩子,因为 3 > 1 。交换 1 和 3 使二叉搜索树有效。
示例 2:
输入:root = [3,1,4,null,null,2]
输出:[2,1,4,null,null,3]
解释:2 不能在 3 的右子树中,因为 2 < 3 。交换 2 和 3 使二叉搜索树有效。
提示:
树上节点的数目在范围 [2, 1000] 内
-231 <= Node.val <= 231 - 1
解题思路:
思路与算法
方法一是显式地将中序遍历的值序列保存在一个 nums 数组中,然后再去寻找被错误交换的节点,但我们也可以隐式地在中序遍历的过程就找到被错误交换的节点 x 和 y。
具体来说,由于我们只关心中序遍历的值序列中每个相邻的位置的大小关系是否满足条件,且错误交换后最多两个位置不满足条件,因此在中序遍历的过程我们只需要维护当前中序遍历到的最后一个节点 pred,然后在遍历到下一个节点的时候,看两个节点的值是否满足前者小于后者即可,如果不满足说明找到了一个交换的节点,且在找到两次以后就可以终止遍历。
这样我们就可以在中序遍历中直接找到被错误交换的两个节点 x 和 y,不用显式建立 nums 数组。
中序遍历的实现有迭代和递归两种等价的写法,在本方法中提供迭代实现的写法。使用迭代实现中序遍历需要手动维护栈。
Python代码:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def recoverTree(self, root: TreeNode) -> None:
"""
Do not return anything, modify root in-place instead.
"""
stack = []
x = None
y = None
pre = None
while stack or root:
while root:
stack.append(root)
root = root.left
root = stack.pop()
if pre and pre.val > root.val:
y = root
if not x:
x = pre
pre = root
root = root.right
x.val, y.val = y.val, x.val
return root