leetcode
leetcode 51 ~ 100
恢复二叉搜索树

恢复二叉搜索树

难度:

标签:

题目描述

给你二叉搜索树的根节点 root ,该树中的 恰好 两个节点的值被错误地交换。请在不改变其结构的情况下,恢复这棵树 

 

示例 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

 

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

代码结果

运行时间: 68 ms, 内存: 15.3 MB


/*
题目思路:
通过中序遍历找到所有节点值,然后排序找到交换前后的正确顺序,最后再遍历一遍树来修复错误的值。
利用Java Stream将树的节点转换为流来处理。
*/
import java.util.*;
 
public class Solution {
    public void recoverTree(TreeNode root) {
        List<Integer> values = new ArrayList<>();
        inorder(root, values);
        List<Integer> sortedValues = values.stream().sorted().collect(Collectors.toList());
        recover(root, new int[]{0}, sortedValues);
    }
 
    private void inorder(TreeNode root, List<Integer> values) {
        if (root == null) return;
        inorder(root.left, values);
        values.add(root.val);
        inorder(root.right, values);
    }
 
    private void recover(TreeNode root, int[] index, List<Integer> sortedValues) {
        if (root == null) return;
        recover(root.left, index, sortedValues);
        root.val = sortedValues.get(index[0]++);
        recover(root.right, index, sortedValues);
    }
}
 

解释

方法:

这个题解使用中序遍历的方法来恢复二叉搜索树。在中序遍历二叉搜索树时,正常情况下节点值应该是递增的。如果出现节点值减小的情况,说明找到了被错误交换的两个节点。第一个错误节点是第一次发现节点值减小时的前一个节点,第二个错误节点是最后一次发现节点值减小时的当前节点。找到这两个节点后,交换它们的值即可恢复二叉搜索树。

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
在中序遍历中,如何准确地识别出第一个和第二个错误节点?请详细解释这两个节点的确定逻辑。
在中序遍历二叉搜索树时,节点的值应该连续递增。当发现一个节点的值小于前一个节点的值时,说明发生了逆序,这是错误节点的一个标志。第一次出现逆序时,前一个节点是第一个错误节点(因为它本应比后面的值小),而当前节点是一个疑似的第二个错误节点。如果之后再次发现逆序,那么更新当前节点为第二个错误节点。这种方式有效地识别出了两个位置错误的节点,第一次逆序的前一个节点和最后一次逆序的当前节点。
🦆
为什么可以确定只交换这两个节点的值就能恢复整个二叉搜索树的正确性?
在二叉搜索树中,如果只有两个节点的位置被错误交换,那么这将导致中序遍历中出现一至两处逆序。通过交换这两个节点,原本被破坏的顺序被恢复,使得所有节点重新满足二叉搜索树的性质:每个节点的左子树中的所有值都小于该节点的值,并且其右子树的所有值都大于该节点的值。这样的交换足以修复由两个节点交换引起的任何顺序错误。
🦆
题解中提到在最坏的情况下,二叉搜索树可能退化为一条链。在这种情况下,递归方法的效率如何?是否有更优的方法来处理这种极端情况?
当二叉搜索树退化为一条链时,树的高度等于节点数,这意味着递归方法的空间复杂度为O(n),因为需要相应的递归调用栈空间。这种情况下,递归方法效率较低。一种更优的方法是使用迭代的中序遍历,配合显式栈来控制空间复杂度。迭代方法可以有效地管理遍历过程,减少系统调用栈的使用,从而优化在极端情况下的空间效率。
🦆
如果在中序遍历过程中只发现一次逆序,请问这种情况下如何处理?是否也是交换这一次逆序中涉及的两个节点的值?
如果在中序遍历中只发现一次逆序,那么这次逆序涉及的两个节点就是错误交换的节点。在这种情况下,直接交换这两个节点的值就可以恢复树的正确性。这是因为只有一次逆序意味着只有这两个节点的位置是错误的,其余部分的顺序是正确的。

相关问题