题目:
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?
思路:
我们先来看看采用O(n)的空间复杂度的算法会怎么做:对于BST而言,在中序遍历的结果中,节点的值一定是严格有序的,然而当交换了其中两个节点之后,就会出现两个错误的位置。那么这个错误的位置有什么特征,又如何确定呢?
举个例子吧:[1, 2, 3, 4, 5, 6]。如果交换了两个节点之后可能会变成[1, 6, 3, 4, 5, 2]。那么如何找到这两个节点呢?对于第一个数,我们只需要找到第一个比它后面的数大的就可以(在本例中是6)。而被交换到后面的小的数怎么确定呢?它其实就是最后一个比自己前面的数小的数(在本例中是2)。这样思路就比较清楚了:我们采用中序遍历,但是只需要记录两个被错误交换的节点即可。遇到第一个比后面的数字大的节点,就记为first;遇到最后一个比前面的数字小的节点,就记为second,最后交换first和second的值即可。
虽然该算法在代码上看只开辟了O(1)的空间,符合题目要求,但是由于涉及到递归,所以在实际运行过程中,栈所占用的空间复杂度准确来讲是O(logn)。然而O(logn)也是很不错的空间复杂度了,可以近似认为是O(1)。
代码:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
void recoverTree(TreeNode* root) {
TreeNode *last = NULL, *first = NULL, *second = NULL;
inOrderTraverse(root, last, first, second);
swap(first->val, second->val);
}
private:
void inOrderTraverse(TreeNode* node, TreeNode* &last, TreeNode* &first, TreeNode* &second) {
if(node == NULL) {
return;
}
inOrderTraverse(node->left, last, first, second);
if(last != NULL && last->val > node->val) {
if(first == NULL) { // find the first
first = last;
}
second = node; // update until the last
}
last = node;
inOrderTraverse(node->right, last, first, second);
}
};