一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第12天,点击查看活动详情。
一、题目
leetcode 恢复二叉搜索树
给你二叉搜索树的根节点 root ,该树中的 恰好 两个节点的值被错误地交换。请在不改变其结构的情况下,恢复这棵树 。
示例 1:
输入:root = [1,3,null,null,2]
输出:[3,1,null,null,2]
解释:3 不能是 1 的左孩子,因为 3 > 1 。交换 1 和 3 使二叉搜索树有效。
示例 2:
输入:root = [3,1,4,null,null,2]
输出:[2,1,4,null,null,3]
解释:2 不能在 3 的右子树中,因为 2 < 3 。交换 2 和 3 使二叉搜索树有效。
提示:
树上节点的数目在范围 [2, 1000] 内
-231 <= Node.val <= 231 - 1
二、题解
二叉搜索树的定义是如果左节点的子树不为空,那么左子树的所有节点值都小于根节点;如果右节点的子树不为空,那么右子树的所有节点值都大于根节点;对于其他的子树也是如此。
方法一 根据二叉搜索树的定义那么对该数进行中序遍历,就是先遍历左节点然后根节点最后右节点的结果必定是升序的。而对于题目所给的二叉搜索树中有可能存在两个节点值被交换了,那么对于中序遍历的结果就不符升序了。因此我们可以先对二叉搜索树进行中序遍历获取结果,然后检查中序遍历结果是否升序,如果是完全升序的那么就可以不用管。如果发现某个元素不符合升序条件,那么这个数肯定是被交换过的节点值,那么另外一个交换节点有可能存在之后的位置,或者与该数节点是相邻的,也就是该数的前一个位置,然后我们先记录下这两个位置,继续遍历其余元素,如果还有不是升序的,那么就把之前位置的与当前位置的交换即可。
三、代码
方法一 Java代码
class Solution {
List<Integer> list = new ArrayList<Integer>();
Integer v1 = null;
Integer v2 = null;
public void recoverTree(TreeNode root) {
getInorder(root);
for (int i = 1; i < list.size(); i++) {
if (list.get(i) < list.get(i - 1)) {
v2 = list.get(i);
if (v1 == null) {
v1 = list.get(i - 1);
}
}
}
swap(root);
}
public void swap(TreeNode node) {
if (node == null) {
return;
}
swap(node.left);
if (node.val == v1) {
node.val = v2;
} else if (node.val == v2) {
node.val = v1;
}
swap(node.right);
}
public void getInorder(TreeNode node) {
if (node == null) {
return;
}
getInorder(node.left);
list.add(node.val);
getInorder(node.right);
}
}
时间复杂度:O(N),首先需要遍历一次二叉树的所有节点获取结果,然后再对结果遍历一次,最后再遍历一次二叉树交换节点。
空间复杂度:O(N),需要一个数组集合存储中序遍历的结果。