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++解法一:

 // O(n) space complexity
class Solution {
public:
void recoverTree(TreeNode *root) {
vector<TreeNode*> list;
vector<int> vals;
inorder(root, list, vals);
sort(vals.begin(), vals.end());
for (int i = ; i < list.size(); ++i) {
list[i]->val = vals[i];
}
}
void inorder(TreeNode *root, vector<TreeNode*> &list, vector<int> &vals) {
if (!root) return;
inorder(root->left, list, vals);
list.push_back(root);
vals.push_back(root->val);
inorder(root->right, list, vals);
}
};

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

C++解法二:

 // Still O(n) space complexity
class Solution {
public:
TreeNode *pre;
TreeNode *first;
TreeNode *second;
void recoverTree(TreeNode *root) {
pre = NULL;
first = NULL;
second = NULL;
inorder(root);
if (first && second) swap(first->val, second->val);
}
void inorder(TreeNode *root) {
if (!root) return;
inorder(root->left);
if (!pre) pre = root;
else {
if (pre->val > root->val) {
if (!first) first = pre;
second = root;
}
pre = root;
}
inorder(root->right);
}
};

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

C++解法三:

 // Now O(1) space complexity
class Solution {
public:
void recoverTree(TreeNode *root) {
TreeNode *first = NULL, *second = NULL, *parent = NULL;
TreeNode *cur, *pre;
cur = root;
while (cur) {
if (!cur->left) {
if (parent && parent->val > cur->val) {
if (!first) first = parent;
second = cur;
}
parent = cur;
cur = cur->right;
} else {
pre = cur->left;
while (pre->right && pre->right != cur) pre = pre->right;
if (!pre->right) {
pre->right = cur;
cur = cur->left;
} else {
pre->right = NULL;
if (parent->val > cur->val) {
if (!first) first = parent;
second = cur;
}
parent = cur;
cur = cur->right;
}
}
}
if (first && second) swap(first->val, second->val);
}
};

LeetCode(99):恢复二叉搜索树的更多相关文章

  1. Java实现 LeetCode 99 恢复二叉搜索树

    99. 恢复二叉搜索树 二叉搜索树中的两个节点被错误地交换. 请在不改变其结构的情况下,恢复这棵树. 示例 1: 输入: [1,3,null,null,2] 1 / 3 \ 2 输出: [3,1,nu ...

  2. Leetcode 99.恢复二叉搜索树

    恢复二叉搜索树 二叉搜索树中的两个节点被错误地交换. 请在不改变其结构的情况下,恢复这棵树. 示例 1: 输入: [1,3,null,null,2] 输出: [3,1,null,null,2] 示例  ...

  3. 【1】【leetcode-99】 恢复二叉搜索树

    (没思路) 99. 恢复二叉搜索树 二叉搜索树中的两个节点被错误地交换. 请在不改变其结构的情况下,恢复这棵树. 示例 1: 输入: [1,3,null,null,2]   1   /  3   \ ...

  4. LeetCode:验证二叉搜索树【98】

    LeetCode:验证二叉搜索树[98] 题目描述 给定一个二叉树,判断其是否是一个有效的二叉搜索树. 假设一个二叉搜索树具有如下特征: 节点的左子树只包含小于当前节点的数. 节点的右子树只包含大于当 ...

  5. Leetcode:235. 二叉搜索树的最近公共祖先

    Leetcode:235. 二叉搜索树的最近公共祖先 Leetcode:235. 二叉搜索树的最近公共祖先 Talk is cheap . Show me the code . /** * Defin ...

  6. Leetcode:530. 二叉搜索树的最小绝对差

    Leetcode:530. 二叉搜索树的最小绝对差 Leetcode:530. 二叉搜索树的最小绝对差 Talk is cheap . Show me the code . /** * Definit ...

  7. 【遍历二叉树】07恢复二叉搜索树【Recover Binary Search Tree】

    开一个指针数组,中序遍历这个二叉搜索树,将节点的指针依次保存在数组里, 然后寻找两处逆序的位置, 中序便利里BST得到的是升序序列 ++++++++++++++++++++++++++++++++++ ...

  8. Leetcode 538. 把二叉搜索树转换为累加树

    题目链接 https://leetcode.com/problems/convert-bst-to-greater-tree/description/ 题目描述 大于它的节点值之和. 例如: 输入: ...

  9. LeetCode 669. 修剪二叉搜索树(Trim a Binary Search Tree)

    669. 修剪二叉搜索树 669. Trim a Binary Search Tree 题目描述 LeetCode LeetCode669. Trim a Binary Search Tree简单 J ...

随机推荐

  1. LOJ #2026「JLOI / SHOI2016」成绩比较

    很好的锻炼推柿子能力的题目 LOJ #2026 题意 有$n$个人$ m$门学科,第$ i$门的分数为不大于$U_i$的一个正整数 定义A「打爆」B当且仅当A的每门学科的分数都不低于B的该门学科的分数 ...

  2. jq的遍历关系元素方法集合

    children .children(selector) 返回被选元素的所有直接子元素,不返回文本节点: 下面例子:给level-2的子元素设置border.比较使用children和find htm ...

  3. 【mmall】url-pattern配置为"/"和"/*"的区别

    我的代码 <!-- springmvc --> <servlet> <servlet-name>springmvc</servlet-name> < ...

  4. 将List的元素通过中文字符串排序

    类customer public class Customer { public String name; public int age; Customer(String name, int age) ...

  5. i春秋 小漏洞也有大梦想

    i春秋上的课,提到了一些概念,学习并记录. 此文主要以了解概念为主,没有代码和实战. 水坑式攻击 百度定义: “水坑式攻击”,是指黑客通过分析被攻击者的网络活动规律,寻找被攻击者经常访问的网站的弱点, ...

  6. 省电优化之WakeLock

    https://blog.csdn.net/qfanmingyiq/article/details/54587664 boolean onStopJob (JobParameters params) ...

  7. php编程 之 php基础三

    1,php里的while循环 循环执行代码块指定的次数,或者当指定的条件为真时循环执行代码块. while实例: <html> <body> <?php $i=1; wh ...

  8. RabbitMQ应用场景

    1.背景 RabbitMQ是一个由erlang开发的AMQP(Advanved Message Queue)的开源实现. 2.应用场景 2.1异步处理 场景说明:用户注册后,需要发注册邮件和注册短信, ...

  9. How to Train Triplet Networks with 100K Identities?

    1. 为什么介绍此文? Triplet net 改进工作之一,主要思想是在大数据集(人脸识别)上的困难样本挖掘.人脸识别工作对于图像对匹配而言很有借鉴意义,共性是特征的提取和样本数据的挖掘. Trip ...

  10. requests支持socks5代理了

    记录下 以前: import socket import socks from requests_html import HTMLSession session=HTMLSession() socks ...