#99.Recover Binary Search Tree
Two elements of a binary search tree (BST) are swapped by mistake.
Recover the tree without changing its structure.
Example 1:
Input: [1,3,null,null,2]
1
/
3
\
2
Output: [3,1,null,null,2]
3
/
1
\
2
Example 2:
Input: [3,1,4,null,null,2]
3
/ \
1 4
/
2
Output: [2,1,4,null,null,3]
2
/ \
1 4
/
3
Follow up:
A solution using O(n) space is pretty straight forward.
Could you devise a constant space solution?
这道题如果用O(n)的空间复杂度是很简单的,直接进行一次中序遍历就好了,所以这题的难点其实在于如何用O(1)的空间复杂度来遍历一个二叉树,老实说一开始我是没有什么思路的,因为无论是用递归还是非递归的方法其空间复杂度都会达到O(n),在查询相关资料后我发现了一种叫做Morris Traversal的方法,其基本思路就是虽然遍历不能改变树的结构,但是只是对最终状态有要求,所以可以在中间加入一些边然后删掉恢复原状态就好了。所以可以利用线索二叉树,让中序遍历的前驱节点指向下一个节点,然后在合适的时候删掉就好了。
具体算法描述如下:
-
如果当前节点的左孩子为空,则输出当前节点并将其右孩子作为当前节点。
-
如果当前节点的左孩子不为空,在当前节点的左子树中找到当前节点在中序遍历下的前驱节点。
a) 如果前驱节点的右孩子为空,将它的右孩子设置为当前节点。当前节点更新为当前节点的左孩子。
b) 如果前驱节点的右孩子为当前节点,将它的右孩子重新设为空(恢复树的形状)。输出当前节点。当前节点更新为当前节点的右孩子。
用以上算法就可以实现一个O(1)空间复杂度的中序遍历,然后我们回到这题本身,有两个节点的值被互换了,一个正常的搜索二叉树中序遍历结果是递增的,我们假设为 a 1 a_1 a1 a 2 a_2 a2… a n a_n an,交换会出现两种情况,一种是两个节点相邻,也就是变成 a 1 a 2 a_1a_2 a1a2… a k a k − 1 a_ka_{k-1} akak−1… a n a_n an, 也有可能两个节点不相邻,也就是变成 a 1 a 2 ⋯ a m a k + 1 ⋯ a m − 1 a k ⋯ a n a_1a_2 \cdots a_ma_{k+1}{\cdots}a_{m-1}a_k{\cdots}a_n a1a2⋯amak+1⋯am−1ak⋯an,第一种情况出现了一个序列下降,也就是 a k a_k ak到 a k − 1 a_{k-1} ak−1, 第二种出现了两种序列下降,也就是 a m a_m am到 a k + 1 a_{k+1} ak+1和 a m − 1 a_{m-1} am−1到 a k a_k ak,这两种情况其实可以归为一种,交换第一个发现降序对的前驱节点和最后一个降序对的后继节点,所以具体代码如下:
class Solution {
public:
void recoverTree(TreeNode* root) {
TreeNode* cur = root;
first = NULL;
second = NULL;
pre = NULL;
while(cur){
TreeNode* next;
if(cur->left == NULL){
next = cur->right;
check(pre,cur);
pre = cur;
}
else{
TreeNode* prev = cur->left;
while(prev->right && prev->right != cur){
prev = prev->right;
}
if(prev->right){
next = cur->right;
prev->right = NULL;
check(pre,cur);
pre = cur;
}
else{
prev->right = cur;
next = cur->left;
}
}
cur = next;
}
swap();
}
private:
void check(TreeNode* pre, TreeNode* cur){
if(pre && pre->val > cur->val){
if(!first){
first = pre;
}
second = cur;
}
}
void swap(){
int tmp = first->val;
first->val = second->val;
second->val = tmp;
}
TreeNode* first;
TreeNode* second;
TreeNode* pre;
};