LeetCode(99):恢复二叉搜索树 Binary Tree Inorder Traversal 二叉树的中序遍历

Hard!

题目描述:

二叉搜索树中的两个节点被错误地交换。

请在不改变其结构的情况下,恢复这棵树。

示例 1:

输入: [1,3,null,null,2]

   1
  /
 3
  \
   2

输出: [3,1,null,null,2]

   3
  /
 1
  \
   2

示例 2:

输入: [3,1,4,null,null,2]

  3
 / \
1   4
   /
  2

输出: [2,1,4,null,null,3]

  2
 / \
1   4
   /
  3

进阶:

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

解题思路:

这道题要求我们复原一个二叉搜索树,说是其中有两个的顺序被调换了,题目要求上说O(n)的解法很直观,这种解法需要用到递归,用中序遍历树,并将所有节点存到一个一维向量中,把所有节点值存到另一个一维向量中,然后对存节点值的一维向量排序,再将排好的数组按顺序赋给节点。这种最一般的解法可针对任意个数目的节点错乱的情况。

C++解法一:

 1 // O(n) space complexity
 2 class Solution {
 3 public:
 4     void recoverTree(TreeNode *root) {
 5         vector<TreeNode*> list;
 6         vector<int> vals;
 7         inorder(root, list, vals);
 8         sort(vals.begin(), vals.end());
 9         for (int i = 0; i < list.size(); ++i) {
10             list[i]->val = vals[i];
11         }
12     }
13     void inorder(TreeNode *root, vector<TreeNode*> &list, vector<int> &vals) {
14         if (!root) return;
15         inorder(root->left, list, vals);
16         list.push_back(root);
17         vals.push_back(root->val);
18         inorder(root->right, list, vals);
19     }
20 };

然后我上网搜了许多其他解法,看到另一种是用双指针来代替一维向量的,但是这种方法用到了递归,也不是O(1)空间复杂度的解法,这里需要三个指针,first,second分别表示第一个和第二个错乱位置的节点,pre指向当前节点的中序遍历的前一个节点。这里用传统的中序遍历递归来做,不过再应该输出节点值的地方,换成了判断pre和当前节点值的大小,如果pre的大,若first为空,则将first指向pre指的节点,把second指向当前节点。这样中序遍历完整个树,若first和second都存在,则交换它们的节点值即可。这个算法的空间复杂度仍为O(n),n为树的高度。

扫描二维码关注公众号,回复: 1539710 查看本文章

C++解法二:

 1 // Still O(n) space complexity
 2 class Solution {
 3 public:
 4     TreeNode *pre;
 5     TreeNode *first;
 6     TreeNode *second;
 7     void recoverTree(TreeNode *root) {
 8         pre = NULL;
 9         first = NULL;
10         second = NULL;
11         inorder(root);
12         if (first && second) swap(first->val, second->val);
13     }
14     void inorder(TreeNode *root) {
15         if (!root) return;
16         inorder(root->left);
17         if (!pre) pre = root;
18         else {
19             if (pre->val > root->val) {
20                 if (!first) first = pre;
21                 second = root;
22             }
23             pre = root;
24         }
25         inorder(root->right);
26     }
27 };

道题的真正符合要求的解法应该用的Morris遍历,这是一种非递归且不使用栈,空间复杂度为O(1)的遍历方法,可参见我之前的博客Binary Tree Inorder Traversal 二叉树的中序遍历,在其基础上做些修改,加入first, second和parent指针,来比较当前节点值和中序遍历的前一节点值的大小,跟上面递归算法的思路相似。

C++解法三:

 1 // Now O(1) space complexity
 2 class Solution {
 3 public:
 4     void recoverTree(TreeNode *root) {
 5         TreeNode *first = NULL, *second = NULL, *parent = NULL;
 6         TreeNode *cur, *pre;
 7         cur = root;
 8         while (cur) {
 9             if (!cur->left) {
10                 if (parent && parent->val > cur->val) {
11                     if (!first) first = parent;
12                     second = cur;
13                 }
14                 parent = cur;
15                 cur = cur->right;
16             } else {
17                 pre = cur->left;
18                 while (pre->right && pre->right != cur) pre = pre->right;
19                 if (!pre->right) {
20                     pre->right = cur;
21                     cur = cur->left;
22                 } else {
23                     pre->right = NULL;
24                     if (parent->val > cur->val) {
25                         if (!first) first = parent;
26                         second = cur;
27                     }
28                     parent = cur;
29                     cur = cur->right;
30                 }
31             }
32         }
33         if (first && second) swap(first->val, second->val);
34     }
35 };

猜你喜欢

转载自www.cnblogs.com/ariel-dreamland/p/9159781.html