二叉搜索树

[leetcode] 99. 恢复二叉搜索树

让人想犯罪 __ 提交于 2019-12-04 02:32:06
99. 恢复二叉搜索树 一开始想了好久没有什么好思路,去网上搜了一下,原来是中序遍历。 二叉搜索树的中序遍历是个(递增)有序数列,利用这个特性,我们可以很巧妙的解决这个题。 先看第二个例子,中序遍历后是:13245,观察发现只有一处发生了降序,只在第二位与第三位发生了降序情况,说明这两个数为异常数,交换3和2的位置重新中序遍历:12345 第一个例子,中序遍历是:321,观察发现有两处发生了降序,第一到第二位,以及第二到第三位,这种情况下交换第一位与第三位即可 实际上题目中只有两个节点被交换了,所以降序情况最多也只会出现两处。所以分两种情况处理即可。 我们再造个例子,看的更直观点: [10 17 15 1 8 12 5] 中序遍历 1 17 8 10 12 15 5 17与3发生了降序,15与5发生了降序,我们将第一个降序的前一个元素与第二个降序的后一个元素,进行交换即可。 当只有一次降序出现时(可以理解为两个降序挤到了一块嘛),降序的前一个元素与降序的后一个元素,进行交换即可。 代码 class Solution { TreeNode p, q, last; void middle(TreeNode root) { if (root == null) return; middle(root.left); if (last != null && last.val > root

Leetcode99 恢复二叉搜索树

空扰寡人 提交于 2019-12-04 02:31:43
写在题目前的话 : 第一次写这个博客以后我发现我 理解错了题目 ,但是我的问题 更具有一般性,更复杂, 所以文章就不改了 题目:只有 两个 结点被错误的交换。 我的:有 任意多个 结点被错误的交换。 题目: 先分析题目:使用O(n)空间复杂度的解法很容易实现,那么我们先看看很容易实现是怎实现的。 算法1: 1、中序遍历二叉树,并将中序序列保存在一个数组Numbers中 2、对Numbesr进行排序 3、中序遍历二叉树,并用Numbers序列按遍历顺序覆盖掉二叉树中的每一个值 此算法即是我想到的空间复杂度为O(n)容易的解法 123的时间复杂度分别为O(N), O(NlogN), O(N),因此上述算法时间复杂度为O(NlogN) 接下来,看一下使用常数空间怎么解决这个问题。 先注意一点 void recoverTree(TreeNode* root) 通过题目给的接口函数可以看出,是值传递。因此通过对原树进行遍历并重新构建一个新树,再把新树根结点赋值给root的方法是不成立的,而且题目说明,树的结构不发生改变,也能够理解到,这个题目是要直接交换树结点的值。 根据之前算法1的启发,其实要做的就是对二叉树进行排序,使得其中序遍历序列为有序序列即可。而中序遍历能够得到什么? 能得到一个按次序访问的结点序列,如果每次访问下一个结点之前,都记录一个之前访问的结点,那么就可以得到一对相邻结点。

Leetcode99:恢复二叉搜索树

随声附和 提交于 2019-12-04 02:30:33
题目描述: 二叉搜索树中的两个节点被错误地交换。请在不改变其结构的情况下,恢复这棵树。 示例 1: 输入: [1,3,null,null,2] 1 / 3 \ 2 输出: [3,1,null,null,2] 3 / 1 \ 2 解法一: 来自: https://leetcode.com/problems/recover-binary-search-tree/discuss/32535/No-Fancy-Algorithm-just-Simple-and-Powerful-In-Order-Traversal 利用树的中序遍历; 解释: 中序遍历二叉树,并维持三个变量:pre,first和second,分别表示:前一个访问的节点,第一个需要交换的节点和第二个需要交换的节点; 中序遍历时,如果是排序二叉树,应该是递增序列;但该数由于存在两个节点发生了交换,所以非递增序列;我们要找的就是破坏了递增规则的第一个节点和第二个节点 如[6,3,4,5,2],这是中序遍历的结果;从后向前遍历; 判断破坏规则的标准是: 找first:找序列中第一次出现的当前节点小于前一节点的位置;则前一节点即为first; 找second:因为此时已经找到first了,之后破坏规则的肯定是值小于前一节点的节点;即找当前节点值小于前一节点值的,即为second 所以,第一个破坏规则的数字是6;第二个破坏规则的是2

leetcode-98-验证二叉搜索树(validat binary search tree)-java

寵の児 提交于 2019-12-04 02:29:33
题目 package pid098; /*验证二叉搜索树 给定一个二叉树,判断其是否是一个有效的二叉搜索树。 假设一个二叉搜索树具有如下特征: 节点的左子树只包含小于当前节点的数。 节点的右子树只包含大于当前节点的数。 所有左子树和右子树自身必须也是二叉搜索树。 示例 1: 输入: 2 / \ 1 3 输出: true 示例 2: 输入: 5 / \ 1 4 / \ 3 6 输出: false 解释: 输入为: [5,1,4,null,null,3,6]。 根节点的值为 5 ,但是其右子节点值为 4 。 }*/ public class main { public static void main(String[] args) { Object[] x=new Object[]{3,1,20}; BinaryTree tree=new BinaryTree(x); tree.printTree(tree.root); test(tree.root); Object[] x2=new Object[]{10,5,15,null,null,6,20}; BinaryTree tree2=new BinaryTree(x2); tree2.printTree(tree2.root); test(tree2.root); } private static void test

Leetcode:99.恢复二叉搜索树

做~自己de王妃 提交于 2019-12-04 02:29:21
二叉搜索树中的两个节点被错误地交换。请在不改变其结构的情况下,恢复这棵树。 示例 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 解题思路: 二叉搜索树:中序遍历中没有逆序对。如果知道什么是中序遍历,还有二叉搜索树,本题只能算是easy。 按照题意只交换了二叉树的两个结点,这也就意味着是排序数组中交换了两个元素的位置,这么一想就会变得容易很多。 1. 交换的两个元素中序遍历相邻。这时只会出现一个逆序对,交换两个逆序对结点的的val即可。 2. 两个元素在中序遍历数组中不相邻。会出现两个逆序对,我们只需记录第一个逆序对的第一个结点,以及第二个逆序对的第二个结点即可,最后交换两个结点的val即可。 只需要记录逆序对的位置即可,因此仅用了常数个空间。 C++代码 #define hasLChild(x) (!(x->left==NULL)) #define hasRChild(x) (!(x->right==NULL)) class Solution { public: void recoverTree(TreeNode* root) { /

LeetCode099——恢复二叉搜索树

旧时模样 提交于 2019-12-04 02:29:10
我的LeetCode代码仓: https://github.com/617076674/LeetCode 原题链接: https://leetcode-cn.com/problems/recover-binary-search-tree/description/ 题目描述: 知识点:二叉搜索树、中序遍历 思路一:中序遍历 这个思路和 LeetCode098——验证二叉搜索树 中的思路二是一致的。 对于一棵二叉搜索树而言,其中序遍历的结果是一个递增序列。我们保存原二叉搜索树中序遍历的结果。再对该结果进行排序后得到另一个序列,比较两个序列中的不同的两个值,即为需要交换的两个错误节点。 这里我采用的是递归的形式实现中序遍历,更多中序遍历算法请见 LeetCode094——二叉树的中序遍历 。 时间复杂度是O(nlogn),其中n为树中的节点个数。空间复杂度也是O(n)。 JAVA代码: public class Solution { List<TreeNode> list; public void recoverTree(TreeNode root) { list = new ArrayList<>(); inorderTraversal(root); List<TreeNode> tempList = new ArrayList<>(list); Collections.sort

[LeetCode]538. 把二叉搜索树转换为累加树

大憨熊 提交于 2019-12-03 21:29:28
题目 给定一个二叉搜索树(Binary Search Tree),把它转换成为累加树(Greater Tree),使得每个节点的值是原来的节点值加上所有大于它的节点值之和。 例如: 输入: 二叉搜索树: 5 / \ 2 13 输出: 转换为累加树: 18 / \ 20 13 来源:力扣(LeetCode) 链接: https://leetcode-cn.com/problems/convert-bst-to-greater-tree 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 题解 使用 反中序遍历 即右根左的顺序遍历 这样只需遍历一遍,因为二叉搜索树的性质保证了是从大到小遍历,每次更新累加值,并加到当前节点上更新节点值即可。 代码 /** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { private int sum = 0; public TreeNode convertBST(TreeNode root) { if (root != null) { convertBST

数据结构与算法二 - 二叉搜索树

匆匆过客 提交于 2019-12-03 20:44:55
1 概述 二叉搜索树,顾名思义,其主要目的用于搜索,它是二叉树结构中最基本的一种数据结构,是后续理解B树、B + 树、红黑树的基础,后三者在具体的工程实践中更常用,比如C++中STL就是利用红黑树做Map,B树用于磁盘上的数据库维护等,后三者均是在二叉搜索树的基础上演变而来的,理解二叉搜索树是学习后者的基础。 与基础的数据结构如链表、堆、栈等基本结构一样,学习二叉搜索树的关键是深入理解访问与操作二叉树的算法及性能分析,本文如下部分首先介绍二叉搜索树的特征;然后重点介绍二叉搜索树的遍历、查找(包括最值查找、前驱后继查找)、以及插入和删除等操作,最后简单进行分析。 2 二叉搜索树的定义及操作 二叉树很简单,表示每个节点最多有两个子节点,二叉搜索树则更作了更近一步的要求,其必须满足如下性质: 设x为二叉搜索树中的一个节点,如果y是x左子树的一个节点( 注:不是直接子节点,是左子树的所有节点 ),则y.key <= x.key;如果y是x右子树的一个节点,则y.key >= x.key 分析:二叉树本身具有固定的结构,上述规定对二叉树中节点之间的关系进行限制,即赋予了二叉树特定的语义,只要满足二叉树的这种语义,就可以直接根据二叉树结构特征更高效地进行查询搜索等操作 如下图1所示: 图1: 二叉搜索树例子 2.1 二叉搜索树的遍历 树的遍历有三种:先序遍历、中序遍历、后序遍历。 先序遍历

二叉搜索树及其相关操作

匿名 (未验证) 提交于 2019-12-03 00:30:01
二叉树(binary tree)是一种树型数据结构,其中它的每个节点最多有两个孩子(可以没有,也可以只有一个)。 二叉搜索树(binary search tree)是一种特殊的二叉树,对每个节点,其左孩子/左子树的关键字值该节点的关键字值;其右孩子/右子树的关键字值都大于该节点的关键字值。 二叉搜索树的平均深度为 O ( log N ) O ( log N ) 。其中, N N 为节点总数。 二叉搜索树的主要操作有:创建(初始化)二叉树,查找关键字Find,返回最大最小关键字FindMax, FindMin,向树中插入元素Insert,删除节点Delete,遍历二叉树。 涉及到二叉树的操作有两种方法实现:递归实现和非递归实现。 一、二叉(搜索)基本数据结构 树是由一个个节点构成,节点的构成成一般为:该节点包含的关键字值(data),left指针指向其左孩子,right指针指向其右孩子。 节点结构的一般声明如下: typedef struct _TreeNode { // 定义二叉查找树的结构 ElemType data; // 数据 struct _TreeNode* left; // 指向左孩子指针 struct _TreeNode* right; // 指向其右孩子指针 }TreeNode, *SearchBTree; // TreeNode表示节点别称,

二叉树的基本操作C++

匿名 (未验证) 提交于 2019-12-03 00:26:01
本文用C++语言写了二叉树的基本操作,包括二叉树的四种遍历方式的递归和非递归写法,二叉查找树的插入,删除,构建,路径搜索,序列化和反序列化,是否镜像等操作,仅供参考。 #include<iostream> #include<stack> #include<queue> #include<vector> #include<string> using namespace std; struct TreeNode { TreeNode *left, *right; int val; TreeNode(int x) :val(x), left(NULL), right(NULL){} }; //前序遍历的递归写法 void helper1(TreeNode *root, vector<int> &res) { if (!root) return; res.push_back(root->val); helper1(root->left, res); helper1(root->right, res); } vector<int> preTraversalRecur(TreeNode *root) { vector<int> res; helper1(root, res); return res; } //前序遍历的非递归写法 vector<int> preTraversalNonrecur