[leetcode] Increasing Order Search Tree

Given a tree, rearrange the tree in in-order so that the leftmost node in the tree is now the root of the tree, and every node has no left child and only 1 right child.

Example 1:
Input: [5,3,6,2,4,null,8,1,null,null,null,7,9]

       5
      / \
    3    6
   / \    \
  2   4    8
 /        / \ 
1        7   9

Output: [1,null,2,null,3,null,4,null,5,null,6,null,7,null,8,null,9]

 1
  \
   2
    \
     3
      \
       4
        \
         5
          \
           6
            \
             7
              \
               8
                \
                 9  

Note:

  1. The number of nodes in the given tree will be between 1 and 100.
  2. Each node will have a unique integer value from 0 to 1000.

分析:题目翻译一下:根据中序遍历,调整二叉树,变成所有的节点都在右子树上。 
思路一:第一个想法,先对树进行中序遍历,保存中序遍历的结果;然后生成一个新树,按照上边的顺序连接起来。
代码如下:
 1 class Solution {
 2     List<Integer> list = new ArrayList<>();
 3     public TreeNode increasingBST(TreeNode root){
 4         zxbl(root);
 5         TreeNode head = new TreeNode(0);
 6         TreeNode node = head;
 7         for ( int n : list ){
 8             //System.out.println(n);
 9             head.right = new TreeNode(n);
10             head = head.right;
11         }
12         return node.right;
13     }
14     private void zxbl(TreeNode root) {
15         if ( root == null ) return;
16         zxbl(root.left);
17         list.add(root.val);
18         zxbl(root.right);
19     }
20 }

    运行时间73ms,显然是一个不太好的方法。

思路二:延续上面的思路,之前list中保存的是root 的值,如果直接保存root是不是更快一点呢?

代码如下:

 1 class Solution {
 2     List<TreeNode> list = new ArrayList<>();
 3     public TreeNode increasingBST(TreeNode root){
 4         zxbl(root);
 5         TreeNode head = new TreeNode(0);
 6         TreeNode node = head;
 7         for ( TreeNode n : list ){
 8             head.right = n;
 9             head = head.right;
10             head.left=null;
11             
12         }
13         return node.right;
14     }
15     private void zxbl(TreeNode root) {
16         if ( root == null ) return;
17         zxbl(root.left);
18         list.add(root);
19         zxbl(root.right);
20     }
21 }

    运行时间36ms,击败74.29%。这里一定要注意红色部分,要给左指针附上null,否则会报错。

思路三:下面想想如何去掉list整个限制呢?也就是在中序遍历的过程中,就实现链接。

代码如下:

 1 class Solution {
 2     TreeNode head;
 3     public TreeNode increasingBST(TreeNode root){
 4         if ( root == null ) return null;
 5         TreeNode node = new TreeNode(0);
 6         head = node;
 7         zxbl(root);
 8         return node.right;
 9     }
10     private void zxbl(TreeNode root) {
11         if ( root == null ) return;
12         zxbl(root.left);
13         root.left=null;
14         head.right = root;
15         head = root;
16         zxbl(root.right);
17     }
18 }

    运行时间34ms,击败82.92%。这里要注意13行红色代码,我的理解是:这里的root就已经是左孩子为null,右孩子不变的一个节点,然后链接到head上。

    我又尝试了如何划归到上面list版本的形式,代码如下:

 1 class Solution {
 2     TreeNode head;
 3     public TreeNode increasingBST(TreeNode root){
 4         if ( root == null ) return null;
 5         TreeNode node = new TreeNode(0);
 6         head = node;
 7         zxbl(root);
 8         return node.right;
 9     }
10     private void zxbl(TreeNode root) {
11         if ( root == null ) return;
12         zxbl(root.left);
13         
14         head.right = root;
15         head = head.right;
16         head.left=null;
17         
18         zxbl(root.right);
19     }
20 }

    基本没什么太大的变化,主要这里就是先下移,然后令左孩子为null;上面的是先令左孩子为null,再下移。一样的。

思路四:虽然上面的解法可以获得答案,但是题目中提示:对树进行rearrange,而不是去新建一棵树。所以下面就是寻找一个新的方法,对原来的树进行操作。

附上discuss中大神的解法:

 1     public TreeNode increasingBST(TreeNode root) {
 2         return helper(root, null);
 3     }
 4 
 5     public TreeNode increasingBST(TreeNode root, TreeNode tail) {
 6         if (root == null) return tail;
 7         TreeNode res = increasingBST(root.left, root);
 8         root.left = null;
 9         root.right = increasingBST(root.right, tail);
10         return res;
11     }

    这个方法比较难以理解,我尽量理解并且讲明白:

    这里要注意一点,它的整个思路就是res = inorder(root.left) + root + inorder(root.right)。

    关键来看一下tail这个变量,tail保存的是比当前节点最近最大的一个节点,而且仅仅在左子树的遍历的时候赋值。比如上面的案例,刚开始就已知遍历到1,这个时候tail指向2,然后回到父节点2,tail指向3,因为2没有右孩子,所以指向父节点3,这个时候tail指向5,然后遍历3的右孩子4,然后回到5。在这里就链接好了1-2-3-4-5。在遍历右子树时,tail为null,最后链接在9上。

    感觉过程太玄学,不容易理解,还是之前的方法更形象一点。

 

posted @ 2018-10-07 22:35  Lin.B  阅读(128)  评论(0编辑  收藏  举报