- Recover Binary Search Tree
中文English
In a binary search tree, (Only) two nodes are swapped. Find out these nodes and swap them. If there no node swapped, return original root of tree.
Example
Example1
Input: {4,5,2,1,3}
Output: {4,2,5,1,3}
Explanation:
Given a binary search tree:
4
/
5 2
/
1 3
return
4
/
2 5
/
1 3
Example2
Input: {1,2,5,4,3}
Output: {4,2,5,1,3}
Given a binary search tree:
1
/
2 5
/
4 3
return
4
/
2 5
/
1 3
解法1:
参考了
http://blog.sina.com.cn/s/blog_eb52001d0102v1z3.html
这个链接讲的很好。
具体的思路,还是通过中序遍历,只不过,不需要存储每个节点,只需要存一个前驱即可。
例如1,4,3,2,5,6
1.当我们读到4的时候,发现是正序的,不做处理
2.但是遇到3时,发现逆序,将4存为第一个错误节点,3存为第二个错误节点
3.继续往后,发现3,2又是逆序了,那么将第2个错误节点更新为2
如果是这样的序列:1,4,3,5,6同上,得到逆序的两个节点为4和3。
注意:
- 什么要替换第二个节点而不是第一个节点:
e.g. The correct BST is below:
【LeetCode】RecoverBinary Search Tree
The inorder traversal is : 1 3 4 6 7 8 10 13 14
Find the place which the order is wrong.
Wrong order: 1 3 8 6 7 4 10 13 14
FIND: 8 6
Then we find: 7 4
8, 6 是错误的序列, 但是,7,4也是错误的序列。
因为8,6前面的序列是正确的,所以8,6一定是后面的序列交换来的。
而后面的应该是比较大的数字,也就是说8一定是被交换过来的。而7,4
中也应该是小的数字4是前面交换过来的。
用反证法来证明:
假设:6是后面交换过来的
推论: 那么8比6还大,那么8应该也是后面交换来的,
这样起码有3个错误的数字了
而题目是2个错误的数字,得证,只应该是8是交换过来的。
结论就是:我们需要交换的是:8, 4.
代码如下:
/**
* Definition of TreeNode:
* class TreeNode {
* public:
* int val;
* TreeNode *left, *right;
* TreeNode(int val) {
* this->val = val;
* this->left = this->right = NULL;
* }
* }
*/
class Solution {
public:
/**
* @param root: the given tree
* @return: the tree after swapping
*/
TreeNode * bstSwappedNode(TreeNode * root) {
if (!root) return NULL;
firstNode = NULL; secondNode = NULL; lastVisitedNode = new TreeNode(INT_MIN);
inOrderTraversal(root);
if (firstNode && secondNode) swap(firstNode->val, secondNode->val);
return root;
}
private:
TreeNode * firstNode, * secondNode, * lastVisitedNode;
void inOrderTraversal(TreeNode * root) {
if (!root) return;
inOrderTraversal(root->left);
if (!firstNode && root->val < lastVisitedNode->val) {
firstNode = lastVisitedNode;
}
if (firstNode && root->val < lastVisitedNode->val) {
secondNode = root;
}
lastVisitedNode = root;
inOrderTraversal(root->right);
}
};
二刷:注意first节点只会更新一次,找到了之后就不变。second节点会一直更新到不能再更新为止!
class Solution {
public:
void recoverTree(TreeNode* root) {
if (!root) return;
inOrderTraversal(root);
swap(first->val, second->val);
return;
}
private:
TreeNode *first = NULL, *second = NULL;
TreeNode *prev = NULL;
void inOrderTraversal(TreeNode *root) {
if (!root) return;
inOrderTraversal(root->left);
if (prev && root->val < prev->val) {
if (!first) first = prev;
second = root;
}
prev = root;
inOrderTraversal(root->right);
}
};
三刷:中序非递归版本
class Solution {
public:
void recoverTree(TreeNode* root) {
if (!root) return;
inOrderTraversal(root);
swap(node1->val, node2->val);
return;
}
private:
TreeNode *node1 = NULL, *node2 = NULL;
stack<TreeNode *> stk;
TreeNode *visited = new TreeNode(0);
TreeNode *pre = NULL;
void inOrderTraversal(TreeNode *root) {
moveLeft(root);
while (!stk.empty()) {
TreeNode *topNode = stk.top();
if ((!topNode->left || topNode->left == visited) && topNode->right != visited) {
//put inorder code here
if (pre && topNode->val < pre->val) {
if (!node1) node1 = pre;
node2 = topNode;
}
pre = topNode;
moveLeft(topNode->right);
}
if ((!topNode->right || topNode->right == visited)) {
//put postorder code here
visited = topNode;
stk.pop();
}
}
}
void moveLeft(TreeNode *root) {
while (root) {
//put preorder code here.
stk.push(root);
root = root->left;
}
}
};
解法2:
直接InOrder遍历,保留两个vector分别记录节点(list)和值(val)。然后将排序后的值拷贝到list里面即可。
代码如下:
class Solution {
public:
TreeNode* bstSwappedNode(TreeNode *root) {
vector<TreeNode*> list;
vector<int> vals;
inorder(root, list, vals);
sort(vals.begin(), vals.end());
for (int i = 0; i < list.size(); ++i) {
list[i]->val = vals[i];
}
return root;
}
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);
}
};