二叉搜索樹中有兩個節點的值被相互交換,還原一個正常的二叉搜索樹。
二叉搜索樹,中序遍歷,每次遍歷的值都會比上次遍歷的值小。根據中序遍歷的這個性質可以找到值錯誤的節點,用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;
}