题目:
二叉搜索树中的两个节点被错误地交换。
请在不改变其结构的情况下,恢复这棵树。
示例 1:
输入: [1,3,null,null,2]
1
/
3
\
2
输出: [3,1,null,null,2]
3
/
1
\
2
示例 2:
输入: [3,1,4,null,null,2]
3
/ \
1 4
/
2
输出: [2,1,4,null,null,3]
2
/ \
1 4
/
3
进阶:
使用 O(n) 空间复杂度的解法很容易实现。
你能想出一个只使用常数空间的解决方案吗?
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/recover-binary-search-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路:
二叉搜索树比较重要的特性:中序遍历是一个递增的过程;如果其中有两个节点交换了,那么这个递增的规则就会被打破,以此为突破口即可解决该问题;
代码分析:
- 方法一(可忽略,仅仅按照题目意思写出答案):先中序遍历,拿到中序遍历的结果,然后遍历结果,出现后面的数比前面的数小则表明这两个数有问题;首先,较大的数被交换后不可能为遍历结果的最后一个数,那么只需要从前往后遍历,第一个比后面的数字大的节点即是被交换的两个数字中的较大的节点;较小的数字被交换后,不可能是遍历结果的最前面一个数字,那么只需要遍历,最后一个(因为较大数字被换到前面去后,较大数字后面的一个正常数字也会出现后面比前面数字小的情况)小于前面的数字的节点即是被交换的两个数字中的较小的节点,然后交换即可;
- 进阶(空间负载度为O(1)): 其实转换一下思路,中序遍历我们就拿当前数字与前面的数字比,如果小于前面的数字就是有问题的,因为题目说了只是交换了两个数字,那么只有两个点可能会出现后面数字小于前面数字,第一个点就是largeNode(被交换的节点中数字较大的节点)后面的正常节点,那么此时的前一个节点就是largeNode,第二个点就是smallNode(被交换的节点中数字较小的节点);所以我们不需要整个中序遍历的序列,只需要记住前一个节点即可;
代码实现:
代码一:
/**
* 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) {
if(root == null) return;
//这里的DFS是中序,函数名忘记标记了;
List<TreeNode> list = DFS(root);
TreeNode nodeLarge = null ,nodeSmall = null ,node,pre,next;
for(int i = 0 ; i < list.size();++i){
if (i == 0) {
pre = null;
} else {
pre = list.get(i-1);
}
if (i == list.size()-1){
next = null;
} else {
next = list.get(i+1);
}
node = list.get(i);
//出现当前节点小于前面节点的情况就把当前节点赋值给nodeSmall,最后一次出现该情况时,node一定就是smallNode
if(pre != null && node.val < pre.val){
nodeSmall = node;
}
//第一次出现当前节点大于后面节点时,node一定就是LargeNode;
if(next != null && nodeLarge == null && node.val > next.val){
nodeLarge = node;
}
}
swap(nodeLarge,nodeSmall);
}
private void swap(TreeNode node1,TreeNode node2){
int val = node1.val;
node1.val = node2.val;
node2.val = val;
}
public List<TreeNode> DFS(TreeNode node){
List<TreeNode> list = new ArrayList<>();
LinkedList<TreeNode> stack = new LinkedList<>();
TreeNode nodeTemp = node;
while(!stack.isEmpty() || nodeTemp != null){
while(nodeTemp != null){
stack.push(nodeTemp);
nodeTemp = nodeTemp.left;
}
nodeTemp = stack.pop();
list.add(nodeTemp);
nodeTemp = nodeTemp.right;
}
return list;
}
}
代码二:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
TreeNode pre = null;
TreeNode nodeLarge = null;
TreeNode nodeSmall = null;
public void recoverTree(TreeNode root) {
if(root == null) return;
DFS(root);
swap(nodeLarge,nodeSmall);
}
private void swap(TreeNode node1,TreeNode node2){
int val = node1.val;
node1.val = node2.val;
node2.val = val;
}
//此处DFS是中序遍历;
public void DFS(TreeNode node){
if(node == null) return;
DFS(node.left);
//第一个出现后面比前面数字小的情况时,pre就是largeNode;
if(nodeLarge == null && pre != null && pre.val > node.val) nodeLarge = pre;
//最后一个出现后面比前面数字小时,node就是smallNode;
if(nodeLarge != null && pre.val > node.val) nodeSmall = node;
pre = node;
DFS(node.right);
}
}