LeetCode(99):恢复二叉搜索树
Posted Ariel_一只猫的旅行
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode(99):恢复二叉搜索树相关的知识,希望对你有一定的参考价值。
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为树的高度。
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 };
以上是关于LeetCode(99):恢复二叉搜索树的主要内容,如果未能解决你的问题,请参考以下文章
⭐算法入门⭐《二叉树 - 二叉搜索树》中等09 —— LeetCode 99. 恢复二叉搜索树