经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C++ » 查看文章
C++实现LeetCode(99.复原二叉搜索树)
来源:jb51  时间:2021/7/19 19:53:46  对本文有异议

[LeetCode] 99. Recover Binary Search Tree 复原二叉搜索树

Two elements of a binary search tree (BST) are swapped by mistake.

Recover the tree without changing its structure.

Example 1:

Input: [1,3,null,null,2]

   1
/
3
\
2

Output: [3,1,null,null,2]

   3
/
1
\
2

Example 2:

Input: [3,1,4,null,null,2]

3
/ \
1   4
/
2

Output: [2,1,4,null,null,3]

  2
/ \
1   4
/
3

Follow up:

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

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

解法一:

  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为树的高度,参见代码如下:

解法二:

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

我们其实也可以使用迭代的写法,因为中序遍历 Binary Tree Inorder Traversal 也可以借助栈来实现,原理还是跟前面的相同,记录前一个结点,并和当前结点相比,如果前一个结点值大,那么更新 first 和 second,最后交换 first 和 second 的结点值即可,参见代码如下:

解法三:

  1. // Always O(n) space complexity
  2. class Solution {
  3. public:
  4. void recoverTree(TreeNode* root) {
  5. TreeNode *pre = NULL, *first = NULL, *second = NULL, *p = root;
  6. stack<TreeNode*> st;
  7. while (p || !st.empty()) {
  8. while (p) {
  9. st.push(p);
  10. p = p->left;
  11. }
  12. p = st.top(); st.pop();
  13. if (pre) {
  14. if (pre->val > p->val) {
  15. if (!first) first = pre;
  16. second = p;
  17. }
  18. }
  19. pre = p;
  20. p = p->right;
  21. }
  22. swap(first->val, second->val);
  23. }
  24. };

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

解法四:

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

到此这篇关于C++实现LeetCode(99.复原二叉搜索树)的文章就介绍到这了,更多相关C++实现复原二叉搜索树内容请搜索w3xue以前的文章或继续浏览下面的相关文章希望大家以后多多支持w3xue!

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号