LeetCode - Medium - 99. Recover Binary Search Tree

拼搏现实的明天。 2022-10-06 11:52 238阅读 0赞

Topic

  • Tree
  • Depth-first Search

Description

https://leetcode.com/problems/recover-binary-search-tree/

You are given the root of a binary search tree (BST), where exactly two nodes of the tree were swapped by mistake. Recover the tree without changing its structure.

Follow up: A solution using O(n) space is pretty straight forward. Could you devise a constant space solution?

Example 1:
33bd0c503ca3787dd452ef87abc2dcfd.png

  1. Input: root = [1,3,null,null,2]
  2. Output: [3,1,null,null,2]
  3. Explanation: 3 cannot be a left child of 1 because 3 > 1. Swapping 1 and 3 makes the BST valid.

Example 2:
078cacd0b21e5ae81a420031e1465d7a.png

  1. Input: root = [3,1,4,null,null,2]
  2. Output: [2,1,4,null,null,3]
  3. Explanation: 2 cannot be in the right subtree of 3 because 2 < 3. Swapping 2 and 3 makes the BST valid.

Constraints:

  • The number of nodes in the tree is in the range [2, 1000].
  • − 2 31 < = N o d e . v a l < = 2 31 − 1 -2^{31} <= Node.val <= 2^{31} - 1 −231<=Node.val<=231−1

Analysis

方法一:用到中序遍历模式迭代版,找出相邻前后位置异常两个节点,放入candidates,这种节点最少有2个,最多有4个。然后,在candidates中找出最小值节点和最大值节点。最后,这两最值节点交换值。

方法二:方法一的改进,不用candidates,迭代找出相邻前后位置异常两个节点,取前者为first,后者为second。然后迭代再找出相邻前后位置异常两个节点,然后取小者为second。(这步可能没用到,试想,已排序的数列中,仅相邻一对数交换位置)。最后,first、second互换节点值。

方法三:Morris Traversal。时杂度O(N),空杂度O(1),没用到栈。

Submission

  1. import java.util.ArrayList;
  2. import java.util.LinkedList;
  3. import java.util.List;
  4. import com.lun.util.BinaryTree.TreeNode;
  5. public class RecoverBinarySearchTree {
  6. //方法一:我写的,用到中序遍历模式
  7. public void recoverTree(TreeNode root) {
  8. TreeNode p = root;
  9. LinkedList<TreeNode> stack = new LinkedList<>();
  10. List<TreeNode> candidates = new ArrayList<>();
  11. TreeNode prev = null;
  12. while(!stack.isEmpty() || p != null) {
  13. if(p != null) {
  14. stack.push(p);
  15. p = p.left;
  16. }else {
  17. TreeNode node = stack.pop();
  18. if(prev != null && prev.val >= node.val) {
  19. candidates.add(prev);
  20. candidates.add(node);
  21. if(candidates.size() == 4) break;
  22. }
  23. prev = node;
  24. p = node.right;
  25. }
  26. }
  27. TreeNode min = candidates.get(0), max = min;
  28. for(TreeNode node : candidates) {
  29. if(node.val < min.val)
  30. min = node;
  31. if(node.val > max.val)
  32. max = node;
  33. }
  34. int temp = min.val;
  35. min.val = max.val;
  36. max.val = temp;
  37. }
  38. //方法二:方法一的改进
  39. public void recoverTree2(TreeNode root) {
  40. LinkedList<TreeNode> stack = new LinkedList<>();
  41. TreeNode first = null, second = null;
  42. TreeNode prev = null, curr = root;
  43. while(!stack.isEmpty() || curr != null) {
  44. if(curr != null) {
  45. stack.push(curr);
  46. curr = curr.left;
  47. }else {
  48. curr = stack.pop();
  49. if(prev != null && prev.val >= curr.val) {
  50. //incorrect smaller node is always found as prev node
  51. if(first == null)
  52. first = prev;
  53. //incorrect larger node is always found as curr node
  54. second = curr;
  55. }
  56. prev = curr;
  57. curr = curr.right;
  58. }
  59. }
  60. int temp = first.val;
  61. first.val = second.val;
  62. second.val = temp;
  63. }
  64. // 方法三:Morris遍历算法
  65. public void recoverTree3(TreeNode root) {
  66. TreeNode pre = null;
  67. TreeNode first = null, second = null;
  68. // Morris Traversal
  69. TreeNode temp = null;
  70. while (root != null) {
  71. if (root.left != null) {
  72. // connect threading for root
  73. temp = root.left;
  74. while (temp.right != null && temp.right != root)
  75. temp = temp.right;
  76. // the threading already exists
  77. if (temp.right != null) {
  78. if (pre != null && pre.val > root.val) {
  79. if (first == null) {
  80. first = pre;
  81. }
  82. second = root;
  83. }
  84. pre = root;
  85. temp.right = null;
  86. root = root.right;
  87. } else {
  88. // construct the threading
  89. temp.right = root;
  90. root = root.left;
  91. }
  92. } else {
  93. if (pre != null && pre.val > root.val) {
  94. if (first == null) {
  95. first = pre;
  96. }
  97. second = root;
  98. }
  99. pre = root;
  100. root = root.right;
  101. }
  102. }
  103. // swap two node values;
  104. if (first != null && second != null) {
  105. int t = first.val;
  106. first.val = second.val;
  107. second.val = t;
  108. }
  109. }
  110. }

Test

  1. import static org.junit.Assert.*;
  2. import org.junit.Test;
  3. import com.lun.util.BinaryTree;
  4. import com.lun.util.BinaryTree.TreeNode;
  5. public class RecoverBinarySearchTreeTest {
  6. @Test
  7. public void test() {
  8. RecoverBinarySearchTree obj = new RecoverBinarySearchTree();
  9. TreeNode root1 = BinaryTree.integers2BinaryTree(1,3,null,null,2);
  10. TreeNode expected1 = BinaryTree.integers2BinaryTree(3,1,null,null,2);
  11. obj.recoverTree(root1);
  12. assertTrue(BinaryTree.equals(root1, expected1));
  13. //---
  14. TreeNode root2 = BinaryTree.integers2BinaryTree(3,1,4,null,null,2);
  15. TreeNode expected2 = BinaryTree.integers2BinaryTree(2,1,4,null,null,3);
  16. obj.recoverTree(root2);
  17. assertTrue(BinaryTree.equals(root2, expected2));
  18. //---
  19. TreeNode root3 = BinaryTree.integers2BinaryTree(3, 9, 6, null, null, 5, 8, null, null, 7, 2);
  20. TreeNode expected3 = BinaryTree.integers2BinaryTree(3, 2, 6, null, null, 5, 8, null, null, 7, 9);
  21. obj.recoverTree(root3);
  22. assertTrue(BinaryTree.equals(root3, expected3));
  23. }
  24. @Test
  25. public void test2() {
  26. RecoverBinarySearchTree obj = new RecoverBinarySearchTree();
  27. TreeNode root1 = BinaryTree.integers2BinaryTree(1,3,null,null,2);
  28. TreeNode expected1 = BinaryTree.integers2BinaryTree(3,1,null,null,2);
  29. obj.recoverTree2(root1);
  30. assertTrue(BinaryTree.equals(root1, expected1));
  31. //---
  32. TreeNode root2 = BinaryTree.integers2BinaryTree(3,1,4,null,null,2);
  33. TreeNode expected2 = BinaryTree.integers2BinaryTree(2,1,4,null,null,3);
  34. obj.recoverTree2(root2);
  35. assertTrue(BinaryTree.equals(root2, expected2));
  36. //---
  37. TreeNode root3 = BinaryTree.integers2BinaryTree(3, 9, 6, null, null, 5, 8, null, null, 7, 2);
  38. TreeNode expected3 = BinaryTree.integers2BinaryTree(3, 2, 6, null, null, 5, 8, null, null, 7, 9);
  39. obj.recoverTree2(root3);
  40. assertTrue(BinaryTree.equals(root3, expected3));
  41. }
  42. @Test
  43. public void test3() {
  44. RecoverBinarySearchTree obj = new RecoverBinarySearchTree();
  45. TreeNode root1 = BinaryTree.integers2BinaryTree(1,3,null,null,2);
  46. TreeNode expected1 = BinaryTree.integers2BinaryTree(3,1,null,null,2);
  47. obj.recoverTree3(root1);
  48. assertTrue(BinaryTree.equals(root1, expected1));
  49. //---
  50. TreeNode root2 = BinaryTree.integers2BinaryTree(3,1,4,null,null,2);
  51. TreeNode expected2 = BinaryTree.integers2BinaryTree(2,1,4,null,null,3);
  52. obj.recoverTree3(root2);
  53. assertTrue(BinaryTree.equals(root2, expected2));
  54. //---
  55. TreeNode root3 = BinaryTree.integers2BinaryTree(3, 9, 6, null, null, 5, 8, null, null, 7, 2);
  56. TreeNode expected3 = BinaryTree.integers2BinaryTree(3, 2, 6, null, null, 5, 8, null, null, 7, 9);
  57. obj.recoverTree3(root3);
  58. assertTrue(BinaryTree.equals(root3, expected3));
  59. }
  60. }

发表评论

表情:
评论列表 (有 0 条评论,238人围观)

还没有评论,来说两句吧...

相关阅读