zoukankan      html  css  js  c++  java
  • 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 };
  • 相关阅读:
    sed
    zabbix时间不同步
    zabbix-agent安装
    zabbix安装(网络)
    sendmail启动报错
    12306:被骂十年不吭声,终成大器
    一文带你看清HTTP所有概念(转)
    为什么 K8s 在阿里能成功(转)
    一文解读融资方式
    一文解读工业互联网 (转)
  • 原文地址:https://www.cnblogs.com/ariel-dreamland/p/9159781.html
Copyright © 2011-2022 走看看