Description
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]
Output: [3,1,null,null,2]
Example 2:
Input: [3,1,4,null,null,2]
Output: [2,1,4,null,null,3]
Follow up:
- A solution using O(n) space is pretty straight forward.
- Could you devise a constant space solution?
Solution
Inorder recursion, time O(n), space O(n)
题意还是很明了的,将BST序列化成inorder形式,然后找到两个in disorder的位置交换即可。需要注意的是,可能会有多个节点in disorder,我们需要找到第一个和最后一个in disorder的位置
。
考虑这个test case: inorder为{1, 2, 3, 4, 5, 6}
交换2和5变成:{1, 5, 3, 4, 2, 6}
交换之后,{5, 3, 4, 2}都不合规矩(即不满足a[i - 1] < a[i] < a[i + 1]),我们只需要交换5和2即可。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public void recoverTree(TreeNode root) {
List<TreeNode> list = new ArrayList<>();
inorder(root, list);
int first = -1;
int second = -1;
for (int i = 0; i < list.size(); ++i) {
if (first < 0 && isDisorder(list, i)) {
first = i;
} else if (first >= 0 && isDisorder(list, i)) {
second = i;
}
}
if (second > 0) {
swap(list, first, second);
}
}
public void inorder(TreeNode root, List<TreeNode> list) {
if (root == null) {
return;
}
inorder(root.left, list);
list.add(root);
inorder(root.right, list);
}
public boolean isDisorder(List<TreeNode> list, int i) {
return (i > 0 && list.get(i).val < list.get(i - 1).val)
|| (i < list.size() - 1 && list.get(i).val > list.get(i + 1).val);
}
public void swap(List<TreeNode> list, int i, int j) {
int tmp = list.get(i).val;
list.get(i).val = list.get(j).val;
list.get(j).val = tmp;
}
}
Inorder recursion, time O(n), space O(h)
添加几个成员变量即可。需要注意first和second的值可能会在同一层被更新(考虑inorder遍历的相邻节点被swap),inorder中需要有两个if条件,而非一个if-else。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
private TreeNode first;
private TreeNode second;
private TreeNode pre = new TreeNode(Integer.MIN_VALUE);
public void recoverTree(TreeNode root) {
inorder(root);
swap(first, second);
}
public void inorder(TreeNode root) {
if (root == null) {
return;
}
inorder(root.left);
if (first == null && root.val < pre.val) {
first = pre; // first should be the first element in disorder
}
if (first != null && root.val < pre.val) { // another independent condition
second = root; // second should be the last element in disorder
}
pre = root;
inorder(root.right);
}
public void swap(TreeNode p, TreeNode q) {
int tmp = p.val;
p.val = q.val;
q.val = tmp;
}
}
Morris traversal, time O(n), space O(1)
由于一旦涉及递归,就不可能达到O(1)的空间复杂度。想要降低消耗,就必须用神奇的Morris traversal啦(which 我不会写也懒得学学了也会忘)。