99. Recover Binary Search Tree
来源:互联网 发布:产品标题怎么优化 编辑:程序博客网 时间:2024/05/16 00:29
Two elements of a binary search tree (BST) are swapped by mistake.
Recover the tree without changing its structure.
Note:
A solution using O(n) space is pretty straight forward. Could you devise a constant space solution?
分析:首先我们最直观的的想法是中序遍历得到中序序列,平衡二叉树的中序序列是非递减有序的。那么问题就转化成了在非递减有序序列中交换了两个数的位置,找出这两个数并恢复有序序列,这个问题可以通过遍历一遍有序序列分下面2步完成:
- 首先找到第一个错误的数first,即第一个比它后缀要大的数
- 然后要找到第一个错误的数应该放置的位置(这就是第二个错误的数),即要找到第一个比first大的数的前驱,这个前驱就是第一个错误的数应该放的位置,也就是第二个错误的数。(注意一个特殊情况{0,1},first为1,没有找到比first大的数,这是second就是最后一个数0)
算法1:我们可以用递归中序遍历(或者使用栈的非递归中序遍历)来实现,但是这样空间复杂度都是O(n)。下面代码是递归中序遍历,可以通过oj
/** * Definition for binary tree * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */class Solution {public: void recoverTree(TreeNode *root) { // IMPORTANT: Please reset any member data you declared, as // the same Solution instance will be reused for each test case. TreeNode *pre = NULL, *first = NULL, *second = NULL; inorder(root, pre, first, second); if(first != NULL) { if(second == NULL)second = pre;//树{0,1}就可能出现这种情况 int tmp = first->val; first->val = second->val; second->val = tmp; } } //pre是中序序列中当前节点的前驱,first、second分别是要找的两个乱序节点 void inorder(TreeNode *root, TreeNode* &pre, TreeNode* &first, TreeNode* &second) { if(root == NULL)return; if(root->left)inorder(root->left, pre, first, second); if(pre != NULL) { if(first == NULL && root->val < pre->val) first = pre; else if(first && root->val > first->val) {second = pre; return;}//两个错误位置都找到就退出 } pre = root; if(root->right)inorder(root->right, pre, first, second); }};
算法2:为了满足O(1)空间复杂度,我们就要使用非递归且不使用栈的中序遍历算法,在leetcode另一个题目Binary Tree Inorder Traversal中,我们提到了Morris Traversal中序遍历算法,它既没有递归,也没有使用栈,而是用了线索二叉树的思想,用闲置的右节点指向中序序列中该节点的后缀,遍历后再恢复树的原始指针。其主要算法步骤如下:
重复以下1、2直到当前节点为空。
1. 如果当前节点的左孩子为空,则输出当前节点并将其右孩子作为当前节点。
2. 如果当前节点的左孩子不为空,在当前节点的左子树中找到当前节点在中序遍历下的前驱节点(即当前节点的左子树的最右节点)。
a) 如果前驱节点的右孩子为空,将它的右孩子设置为当前节点(利用这个空的右孩子指向它的后缀)。当前节点更新为当前节点的左孩子。
b) 如果前驱节点的右孩子为当前节点,将它的右孩子重新设为空(恢复树的形状)。输出当前节点。当前节点更新为当前节点的右孩子。
只要在上述遍历算法上加几行代码(红色代码)判断元素是否有序的代码就可以找出乱序的两个节点(同样也是利用上面的思想分别找到第一第二个乱序数)
需要注意的是:不能像上面的算法1那样,找到两个错误的数就退出循环。因为Morris Traversal算法破坏了原来的树的结构,需要整个循环都运行完成恢复树的结构。不然的话,就如本文第一条评论中那样,oj会出现TLE错误
/** * Definition for binary tree * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */class Solution {public: void recoverTree(TreeNode *root) { // IMPORTANT: Please reset any member data you declared, as // the same Solution instance will be reused for each test case. //first,second 分别指向两个错误的节点,parent保存中序访问中当前节点的前驱 TreeNode *first = NULL, *second = NULL, *parent = NULL; TreeNode *current = root, *pre = NULL; while(current != NULL) { if(current->left == NULL) { if(parent != NULL) { if(first == NULL && current->val < parent->val) first = parent; else if(first && !second && current->val > first->val) second = parent; } parent = current; current = current->right; } else { /* Find the inorder predecessor of current */ pre = current->left; while(pre->right != NULL && pre->right != current) pre = pre->right; if(pre->right == NULL) { /* Make current as right child of its inorder predecessor */ pre->right = current; current = current->left; } else { /* Revert the changes made in if part to restore the original tree i.e., fix the right child of predecssor */ //这里parent肯定不等于NULL if(first == NULL && current->val < parent->val) first = parent; else if(first && !second && current->val > first->val) second = parent; parent = current; pre->right = NULL; current = current->right; } } } if(first != NULL) { if(second == NULL)second = parent;//树{0,1}就可能出现这种情况 int tmp = first->val; first->val = second->val; second->val = tmp; } }};
15.9.13更新
----------------
要找到错误交换的两个节点,可以中序遍历,first节点为第一个比前面节点小的节点的前一个节点,sec节点为最后一个比前面小的节点。
- 99.Recover Binary Search Tree
- 99. Recover Binary Search Tree
- 99. Recover Binary Search Tree
- 99. Recover Binary Search Tree
- 99. Recover Binary Search Tree
- 99. Recover Binary Search Tree
- 99. Recover Binary Search Tree
- 99. Recover Binary Search Tree
- 99. Recover Binary Search Tree
- 99. Recover Binary Search Tree
- 99. Recover Binary Search Tree
- 99. Recover Binary Search Tree
- 99. Recover Binary Search Tree
- 99. Recover Binary Search Tree
- 99. Recover Binary Search Tree
- 99. Recover Binary Search Tree
- 99. Recover Binary Search Tree
- 99. Recover Binary Search Tree
- 8.7总结
- Zend Framework2 - 在Controller使用自定义插件plugins 和 视图助手Helper
- codeforces
- 类的锁
- bzoj3757: 苹果树
- 99. Recover Binary Search Tree
- 【网络协议】互联网协议入门(一)
- linux 内核配置与编译
- c++使用应用框架
- Winform开发全套31个UI组件开源共享
- 【Java多线程】之十一:Java BlockingQueue Example implementing Producer Consumer Problem
- Linux - 主机的细部权限规划:ACL 的使用
- liunx 系统下mysql数据库的jdbc连接使用
- 1009 迷宫问题