[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:
- 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上。
感覺過程太玄學,不容易理解,還是之前的方法更形象一點。
[leetcode] Increasing Order Search Tree