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:
- The number of nodes in the given tree will be between 1 and 100.
- 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上。
感觉过程太玄学,不容易理解,还是之前的方法更形象一点。