• [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上。

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

  • 相关阅读:
    CF666E Forensic Examination 广义后缀自动机 + 线段树合并 + 树上倍增
    NOI2018 你的名字 后缀自动机 + 线段树合并 + 可持久化
    [NOI2018]你的名字(68pts) 后缀自动机
    [SDOI2016]生成魔咒 后缀自动机
    洛谷P3369 【模板】普通平衡树 01trie/骚操作
    BZOJ2161: 布娃娃 整体二分
    超市购物功能,会员卡功能,会员卡积分查询功能,会员卡奖品功能,自己练手函数程序
    可变长参数,函数的嵌套,名称空间,关键字
    函数基础,函数返回值,函数调用的3中方式,形参与实参
    文件的详细操作
  • 原文地址:https://www.cnblogs.com/boris1221/p/9751872.html
Copyright © 2020-2023  润新知