Leetcode: Recover Binary Search Tree

Two elements of a binary search tree (BST) are swapped by mistake.

Recover the tree without changing its structure.

Note:
A solution using O(n) space is pretty straight forward. Could you devise a constant space solution?

难度:89. 这道题是要求恢复一颗有两个元素调换错了的二叉查找树。一开始拿到可能会觉得比较复杂,其实观察出规律了就比较简单。主要还是利用二叉查找树的主要性质,就是中序遍历是有序的性质。那么如果其中有元素被调换了,意味着中序遍历中必然出现违背有序的情况。那么会出现几次呢?有两种情况,如果是中序遍历相邻的两个元素被调换了,很容易想到就只需会出现一次违反情况,只需要把这个两个节点记录下来最后调换值就可以;如果是不相邻的两个元素被调换了,举个例子很容易可以发现,会发生两次逆序的情况,那么这时候需要调换的元素应该是第一次逆序前面的元素,和第二次逆序后面的元素。比如1234567,1和5调换了,会得到5234167,逆序发生在52和41,我们需要把4和1调过来,那么就是52的第一个元素,41的第二个元素调换即可。如果是1和3调换了,会得到3214567,逆序发生在32和21,那么需要调换的是32的第一个元素,21的第二个元素。所以我们要做的就是把逆序的所有元素都依次存在一个ArrayList里面,不管是一次逆序还是两次,只需要把一头一尾的两个元素完成值交换,就好了。


搞清楚了规律就容易实现了,中序遍历寻找逆序情况,调换的第一个元素,永远是第一个逆序的第一个元素,而调换的第二个元素如果只有一次逆序,则是那一次的后一个,如果有两次逆序则是第二次的后一个。算法只需要一次中序遍历,所以时间复杂度是O(n),空间是栈大小O(logn)。

 1 public class Solution {
 2     
 3     TreeNode firstElement = null;
 4     TreeNode secondElement = null;
 5     // The reason for this initialization is to avoid null pointer exception in the first comparison when prevElement has not been initialized
 6     TreeNode prevElement = new TreeNode(Integer.MIN_VALUE);
 7     
 8     public void recoverTree(TreeNode root) {
 9         
10         // In order traversal to find the two elements
11         traverse(root);
12         
13         // Swap the values of the two nodes
14         int temp = firstElement.val;
15         firstElement.val = secondElement.val;
16         secondElement.val = temp;
17     }
18     
19     private void traverse(TreeNode root) {
20         
21         if (root == null)
22             return;
23             
24         traverse(root.left);
25         
26         // Start of "do some business", 
27         // If first element has not been found, assign it to prevElement (refer to 6 in the example above)
28         if (firstElement == null && prevElement.val >= root.val) {
29             firstElement = prevElement;
30         }
31     
32         // If first element is found, assign the second element to the root (refer to 2 in the example above)
33         if (firstElement != null && prevElement.val >= root.val) {
34             secondElement = root;
35         }        
36         prevElement = root;
37 
38         // End of "do some business"
39 
40         traverse(root.right);
41 }

 

注意交换两个节点的做法,不能交换两个引用变量,这样对象不受影响,要改需要通过引用变量去访问对应的对象,去改对应对象的内容,只改引用变量的指向对于对象不会有影响

转载于:https://www.cnblogs.com/EdwardLiu/p/3980479.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值