1.法一
既然是BST,那么中序遍历后的数列一定是顺序的,假如不满足条件的话只需要遍历数列就行了,就可以找到问题的地点。最原始粗暴的办法就是排序获得的序列肯定会得到原来的序列样子,然后根据新的序列建立一个新的BST。哈哈,但是这样的空间使用太大了,简单的一点的方式就是将树的节点记录一下,然后找到问题了只需要交换问题节点就是了。我们需要一个外部空间来存放和记录节点,,,,还是消耗了空间。
public void recoverTree(TreeNode root) {
List<TreeNode> nodes = new ArrayList<>();
inOrder(root, nodes);
TreeNode first = null;
TreeNode second = null;
for (int i = 0; i < nodes.size() - 1; i++) {
TreeNode node1 = nodes.get(i);
TreeNode node2 = nodes.get(i + 1);
if (node1.val > node2.val) {
//多种情况
if (first == null) {
first = node1;
second = node2;
} else {
second = node2;
}
}
}
int temp = first.val;
first.val = second.val;
second.val = temp;
}
public void inOrder(TreeNode root, List<TreeNode> list) {
if (root != null) {
inOrder(root.left, list);
list.add(root);
inOrder(root.right, list);
}
}
要注意的是,问题节点不一定是相邻的,我们要找到问题的第一个和最后一个节点配对就可以了。毕竟题目中说了只有两个地方交换出错,说明其他节点基本都是相对有序的
2.法二
使用递归回溯的方法。显然是遍历树然后找出问题节点,BST的遍历主旋律就是中序遍历。根据中序遍历和BST的性质,我们发现正常情况下遍历的前一个节点一定是小于遍历的后一个节点的。一旦出现了不满足这个条件的情况就说明有问题,就应该记录下来。同理,根据题意这样的地方应该有两处。分别记录相应的节点然后在后面进行数据的交换就行了。
TreeNode prev = null;
TreeNode first = null;
TreeNode second = null;
public void recoverTree(TreeNode root) {
inOrder(root);
int val = first.val;
first.val = second.val;
second.val = val;
}
private void inOrder(TreeNode root) {
if (root == null) {
return;
}
inOrder(root.left);
//find the mistake element
if (prev != null && prev.val > root.val) {
if (first == null) {
first = prev;
second = root;
} else
second = root;
}
prev = root;
inOrder(root.right);
}