Given a singly linked list where elements are sorted in ascending order, convert it to a height balanced BST.
难度70,与Convert Sorted Array to Binary Search Tree问题相似,这道题的做法就是,我们需要中点来做每一层树的根,问题在于,对于一个链表我们是不能常量时间访问它的中间元素的。于是我的想法是花O(N)的时间把链表里面的元素先存到一个数组或者ArrayList里面,这样就有了一个sorted的数组或者ArrayList,我们就很容易对它递归来建立一个height balanced BST
1 /** 2 * Definition for singly-linked list. 3 * public class ListNode { 4 * int val; 5 * ListNode next; 6 * ListNode(int x) { val = x; next = null; } 7 * } 8 */ 9 /** 10 * Definition for binary tree 11 * public class TreeNode { 12 * int val; 13 * TreeNode left; 14 * TreeNode right; 15 * TreeNode(int x) { val = x; } 16 * } 17 */ 18 public class Solution { 19 public TreeNode sortedListToBST(ListNode head) { 20 if (head == null) return null; 21 ListNode dummy = new ListNode(-1); 22 dummy.next = head; 23 ListNode cursor = dummy; 24 int count = 0; 25 while (cursor.next != null) { 26 count++; 27 cursor = cursor.next; 28 } 29 int[] array = new int[count]; 30 cursor = dummy; 31 for (int i = 0; i < count; i++) { 32 array[i] = cursor.next.val; 33 cursor = cursor.next; 34 } 35 TreeNode result = helper(array, 0, array.length - 1); 36 return result; 37 } 38 39 public TreeNode helper(int[] array, int begin, int end) { 40 if (begin > end) return null;42 int mid = (begin + end) / 2; 43 TreeNode root = new TreeNode(array[mid]); 44 root.left = helper(array, begin, mid - 1); 45 root.right = helper(array, mid + 1, end); 46 return root; 47 } 48 }
用ArrayList的做法:
1 /** 2 * Definition for singly-linked list. 3 * public class ListNode { 4 * int val; 5 * ListNode next; 6 * ListNode(int x) { val = x; next = null; } 7 * } 8 */ 9 /** 10 * Definition for binary tree 11 * public class TreeNode { 12 * int val; 13 * TreeNode left; 14 * TreeNode right; 15 * TreeNode(int x) { val = x; } 16 * } 17 */ 18 public class Solution { 19 public TreeNode sortedListToBST(ListNode head) { 20 if (head == null) return null; 21 22 ArrayList<Integer> listNode = new ArrayList<Integer>(); 23 while(head != null){ 24 listNode.add(head.val); 25 head = head.next; 26 } 27 int left = 0; 28 int right= listNode.size()-1; 29 return helper(listNode, left, right); 30 } 31 32 public TreeNode helper(ArrayList<Integer> listNode, int left, int right){ 33 if(left>right) return null; 34 35 TreeNode node = new TreeNode(0); 36 int mid = (left+right)/2; 37 node.val = listNode.get(mid); 38 node.left = helper(listNode, left, mid-1); 39 node.right = helper(listNode, mid+1, right); 40 return node; 41 } 42 }
Code Ganker有一个做法,整体过程就是一次中序遍历,时间复杂度是O(n),空间复杂度是栈空间O(logn)加上结果的空间O(n),额外空间是O(logn),总体是O(n)。代码如下:我的额外空间是O(N),他的做法比我优。
他的做法精髓在于:1. helper函数里递归实现了树的inorder访问,ArrayList<ListNode> list中list.get(0).val存的就是当前树inorder遍历正遍历到的节点其value值。我们依次把LinkedList里面的节点挨个添加到list.get(0),由于LinkedList是sorted的,所以LinkedList里面的点与BST inorder遍历的各个点是一一对应的,我们只需要用当前LinkedList节点的val去创建BST当前的节点就好了。
2. helper函数的 int l, int r看似不影响中序遍历,但是却帮助我们判断什么时候当前节点是null,作用就跟中序遍历递归写法里面的判空语句 if(root == null)return; 一样
1 public TreeNode sortedListToBST(ListNode head) { 2 if(head == null) 3 return null; 4 ListNode cur = head; 5 int count = 0; 6 while(cur!=null) 7 { 8 cur = cur.next; 9 count++; 10 } 11 ArrayList<ListNode> list = new ArrayList<ListNode>(); 12 list.add(head); 13 return helper(list,0,count-1); 14 } 15 private TreeNode helper(ArrayList<ListNode> list, int l, int r) 16 { 17 if(l>r) 18 return null; 19 int m = (l+r)/2; 20 TreeNode left = helper(list,l,m-1); 21 TreeNode root = new TreeNode(list.get(0).val); 22 root.left = left; 23 list.set(0,list.get(0).next); 24 root.right = helper(list,m+1,r); 25 return root; 26 }
注意这个代码里面11行-12行,为什么要用一个ArrayList来装载ListNode head再以这个ArrayList作为参数参与递归?这是一个很好的java函数参数问题。如果直接用ListNode head作为参数参与递归,代码如下,这样做是会报错的。原因已经写在《Summary: Java中函数参数的传递》这篇博文里面,这个情况就是里面描述的“(二)对象类型参数:传引用,方法体内改变形参引用,不会改变实参的引用”。在下面代码的22行“node = node.next;” 这里形参引用ListNode node发生了改变, 指向下一个,但是调用它的外层helper函数中的实参ListNode node没有发生任何变化,并没有指向下一个。要想让外层函数的node变化,一个方法是:把node放在ArrayList的index 0处,每次修改index 0的内容,传递ArrayList,这样实参也变化了。
1 public class Solution { 2 public TreeNode sortedListToBST(ListNode head) { 3 if(head == null) 4 return null; 5 ListNode cur = head; 6 int count = 0; 7 while(cur!=null) 8 { 9 cur = cur.next; 10 count++; 11 } 12 return helper(head,0,count-1); 13 } 14 private TreeNode helper(ListNode node, int l, int r) 15 { 16 if(l>r) 17 return null; 18 int m = (l+r)/2; 19 TreeNode left = helper(node,l,m-1); 20 TreeNode root = new TreeNode(node.val); 21 root.left = left; 22 node = node.next; 23 root.right = helper(node,m+1,r); 24 return root; 25 } 26 }