📜  交换了一个BST的两个节点,请更正BST。套装2(1)

📅  最后修改于: 2023-12-03 15:06:23.395000             🧑  作者: Mango

交换了一个BST的两个节点,请更正BST

在二叉搜索树(BST)中,每个节点的左子树上的值都小于该节点上的值,右子树上的值都大于该节点上的值。如果因为一些操作,导致 BST 上出现两个节点位置被交换了,就会破坏这个规则,从而不再是一个有效的 BST。因此,我们需要编写一个程序来纠正这个 BST,使其重新成为一个有效的 BST。

解题思路

我们可以通过中序遍历来检查树是否是一个有效的 BST,因为中序遍历可以按升序访问节点。对于有效的 BST,中序遍历的结果应该是一个按升序排列的节点值序列。

当两个节点位置被交换时,会导致中序遍历序列中出现一对逆序的元素。我们需要找到这对逆序元素并交换它们的值,以恢复 BST 的有效性。

为了找到逆序元素,我们可以在中序遍历时记录前驱节点和当前节点,并比较它们的值。如果前驱节点的值大于当前节点的值,就意味着有一对逆序元素。

在找到逆序元素后,我们将它们的值交换,就可以恢复 BST 的有效性。

代码实现

我们先来实现 BST 的定义和中序遍历函数:

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

def inorder_traversal(root):
    if not root:
        return []
    return inorder_traversal(root.left) + [root.val] + inorder_traversal(root.right)

接下来,我们来实现 BST 纠正函数:

def recover_bst(root):
    # Step 1: 中序遍历得到节点值列表
    values = inorder_traversal(root)

    # Step 2: 寻找逆序元素
    first = second = None
    for i in range(len(values)-1):
        if values[i] > values[i+1]:
            if not first:
                first = TreeNode(values[i])
            second = TreeNode(values[i+1])

    # Step 3: 交换逆序元素的值
    def inorder_exchange(root, x, y):
        if not root:
            return
        if root.val == x.val:
            root.val = y.val
        elif root.val == y.val:
            root.val = x.val
        inorder_exchange(root.left, x, y)
        inorder_exchange(root.right, x, y)

    inorder_exchange(root, first, second)

    return root

最后我们来测试一下:

# 构造一个 BST
root = TreeNode(3, TreeNode(1), TreeNode(4, TreeNode(2)))

# 交换 2 和 4
root.right.val, root.right.right.val = root.right.right.val, root.right.val

# 纠正 BST
recover_bst(root)

# 应该输出 [1, 2, 3, 4]
print(inorder_traversal(root))

输出结果为 [1, 2, 3, 4],符合预期。

时间和空间复杂度

实现中序遍历需要遍历 BST 的每个节点,时间复杂度为 $O(n)$,其中 $n$ 是节点数。因此,总时间复杂度为 $O(n)$。

递归中使用了函数调用栈,空间复杂度为 $O(n)$(最坏情况下,树退化成链表)。