题目:

给你二叉搜索树的根节点 root ,该树中的两个节点被错误地交换。请在不改变其结构的情况下,恢复这棵树。
进阶:使用 O(n) 空间复杂度的解法很容易实现。你能想出一个只使用常数空间的解决方案吗?

示例 1:
99. 恢复二叉搜索树 - 图1
输入:root = [1,3,null,null,2]
输出:[3,1,null,null,2]
解释:3 不能是 1 左孩子,因为 3 > 1 。交换 1 和 3 使二叉搜索树有效。

示例 2:
99. 恢复二叉搜索树 - 图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

解答:

这道题难点,是找到那两个交换节点,把它交换过来就行了。
这里我们二叉树搜索树的中序遍历(中序遍历遍历元素是递增的)
如下图所示,中序遍历顺序是 4,2,3,1,我们只要找到节点 4 和节点 1 交换顺序即可!
99. 恢复二叉搜索树 - 图3
这里我们有个规律发现这两个节点:

  • 第一个节点,是第一个按照中序遍历时候前一个节点大于后一个节点,我们选取前一个节点,这里指节点 4;
  • 第二个节点,是在第一个节点找到之后,后面出现前一个节点大于后一个节点,我们选择后一个节点,这里指节点 1;

对于中序遍历,我们有两种方法。

  • 方法一:迭代
  • 方法二:递归
  1. //方法一:迭代
  2. /**
  3. * Definition for a binary tree node.
  4. * public class TreeNode {
  5. * int val;
  6. * TreeNode left;
  7. * TreeNode right;
  8. * TreeNode(int x) { val = x; }
  9. * }
  10. */
  11. class Solution {
  12. public void recoverTree(TreeNode root) {
  13. Deque<TreeNode> stack = new LinkedList<>();
  14. TreeNode firstNode = null;
  15. TreeNode secondNode = null;
  16. TreeNode pre = new TreeNode(Integer.MIN_VALUE);
  17. TreeNode p = root;
  18. while (p != null || !stack.isEmpty()) {
  19. while (p != null) {
  20. stack.push(p);
  21. p = p.left;
  22. }
  23. p = stack.pop();
  24. if (firstNode == null && pre.val > p.val) firstNode = pre;
  25. if (firstNode != null && pre.val > p.val) secondNode = p;
  26. pre = p;
  27. p = p.right;
  28. }
  29. int tmp = firstNode.val;
  30. firstNode.val = secondNode.val;
  31. secondNode.val = tmp;
  32. }
  33. }
  1. //方法二:递归
  2. /**
  3. * Definition for a binary tree node.
  4. * public class TreeNode {
  5. * int val;
  6. * TreeNode left;
  7. * TreeNode right;
  8. * TreeNode(int x) { val = x; }
  9. * }
  10. */
  11. class Solution {
  12. TreeNode firstNode = null;
  13. TreeNode secondNode = null;
  14. TreeNode preNode = new TreeNode(Integer.MIN_VALUE);
  15. public void recoverTree(TreeNode root) {
  16. in_order(root);
  17. int tmp = firstNode.val;
  18. firstNode.val = secondNode.val;
  19. secondNode.val = tmp;
  20. }
  21. private void in_order(TreeNode root) {
  22. if (root == null) return;
  23. in_order(root.left);
  24. if (firstNode == null && preNode.val > root.val) firstNode = preNode;
  25. if (firstNode != null && preNode.val > root.val) secondNode = root;
  26. preNode = root;
  27. in_order(root.right);
  28. }
  29. }