二叉搜索树中有两个节点的值被相互交换,还原一个正常的二叉搜索树。
二叉搜索树,中序遍历,每次遍历的值都会比上次遍历的值小。根据中序遍历的这个性质可以找到值错误的节点,用first表示上一次遍历的节点,用second表示当前遍历的节点,但是我们不能确定到底哪一个才是错误的节点,继续遍历,如果接下来没有发现错误的节点,则交换上次发现的两个错误节点即可。如果接下来又发现了错误的节点,则说明现在遍历的节点和first节点是错误节点,交换两个节点的值。代码如下:
public void recoverTree(TreeNode root) {
//use inorder traversal to detect incorrect node
inOrder(root);
int temp = first.val;
first.val = second.val;
second.val = temp;
}
TreeNode prev = null;
TreeNode first = null;
TreeNode second = null;
public void inOrder(TreeNode root){
if(root == null) return;
//search left tree
inOrder(root.left);
//in inorder traversal of BST, prev should always have smaller value than current value
if(prev != null && prev.val >= root.val){
//incorrect smaller node is always found as prev node
if(first == null) first = prev;
//incorrect larger node is always found as curr(root) node
second = root;
}
//update prev node
prev = root;
//search right tree
inOrder(root.right);
}
基于morris中序遍历的恢复。O(1)的空间。
public void recoverTree(TreeNode root) {
//Morris-traversal
TreeNode first = null;
TreeNode second = null;
TreeNode pred = null; //rightmost node in left tree
TreeNode prev = null;
TreeNode curr = root;
while(curr != null){
//for each node, we compare it with prev node as we did in in-order-traversal
if(prev != null && curr.val <= prev.val){
if(first == null) first = prev;
second = curr;
}
if(curr.left != null){
//got left tree, then let's locate its rightmost node in left tree
pred = curr.left;
//we may have visited the left tree before, and connect the rightmost node with curr node (root node)
while(pred.right != null && pred.right != curr){
pred = pred.right;
}
if(pred.right == curr){
//if this left tree has been visited before, then we are done with it
//cut the connection with currNode and start visit curr's right tree
pred.right = null;
prev = curr;
curr = curr.right;
}else{
//if this left tree has not been visited before, then we create a back edge from rightmost node
// to curr node, so we can return to the start point after done the left tree
pred.right = curr;
curr = curr.left;
}
}else{
//no left tree, then just visit its right tree
prev = curr;
curr = curr.right;
}
}
int temp = first.val;
first.val = second.val;
second.val = temp;
}