Given a singly linked list where elements are sorted in ascending order, convert it to a height balanced BST.
Thoughts
If you are given an array, the problem is quite straightforward. But things get a little more complicated when you have a singly linked list instead of an array. Now you no longer have random access to an element in O(1) time. Therefore, you need to create nodes bottom-up, and assign them to its parents. The bottom-up approach enables us to access the list in its order at the same time as creating nodes.
Java Solution
// Definition for singly-linked list. class ListNode { int val; ListNode next; ListNode(int x) { val = x; next = null; } } // Definition for binary tree class TreeNode { int val; TreeNode left; TreeNode right; TreeNode(int x) { val = x; } } public class Solution { static ListNode h; public TreeNode sortedListToBST(ListNode head) { if (head == null) return null; h = head; int len = getLength(head); return sortedListToBST(0, len - 1); } // get list length public int getLength(ListNode head) { int len = 0; ListNode p = head; while (p != null) { len++; p = p.next; } return len; } // build tree bottom-up public TreeNode sortedListToBST(int start, int end) { if (start > end) return null; // mid int mid = (start + end) / 2; TreeNode left = sortedListToBST(start, mid - 1); TreeNode root = new TreeNode(h.val); h = h.next; TreeNode right = sortedListToBST(mid + 1, end); root.left = left; root.right = right; return root; } } |
other solution would be
as we know #size of list,. we build just dummy binary tree, halfing size, and then do in-order traverse
tree and list to change value for nodes.
instance variable right?
This version has smaller constants.
class ListNode {
ListNode next;
int data;
public ListNode(int data) {
this.data = data;
this.next = null;
}
};
class TreeNode {
TreeNode left;
TreeNode right;
int data;
public TreeNode(int data) {
this.data = data;
this.left = null;
this.right = null;
}
};
public class sortedListToBalancedBST {
public int getListLen(ListNode L) {
ListNode n = L;
if (n == null)
return 0;
int k = 1;
while (n.next != null) {
n = n.next;
k++;
}
return k;
}
public ListNode getKthElement(ListNode L, int k) {
if (L == null)
return null;
ListNode n = L;
int i = 0;
while (n.next != null && i < k) {
n = n.next;
i++;
}
return n;
}
public TreeNode do_BBST(ListNode L) {
int len = getListLen(L);
return build_BBST(L, len);
}
public TreeNode build_BBST(ListNode head, int len) {
if (len == 0)
return null;
if (len == 1)
return new TreeNode(head.data);
int p = len / 2;
ListNode pNode = getKthElement(head, p);
TreeNode L = build_BBST(head, p);
TreeNode R = build_BBST(pNode.next, len - p - 1);
TreeNode n = new TreeNode(pNode.data);
n.left = L;
n.right = R;
return n;
}
}
Can we have iterative approach for program?
public class Solution {
public TreeNode sortedListToBST(ListNode head) {
if (head == null) {
return null;
}
ListNode end = head;
while (end.next != null) {
end = end.next;
}
return sortedListToBST(head, end);
}
public TreeNode sortedListToBST(ListNode head, ListNode end) {
if (end.next == head) { //basically same ideas as start > end; occurs when one node left so head > midPrev and mid.next > end
return null;
}
ListNode midPrev = findMidPrev(head, end);
ListNode mid = midPrev.next;
TreeNode node = new TreeNode(mid.val);
node.left = sortedListToBST(head, midPrev);
node.right = sortedListToBST(mid.next, end);
return node;
}
//return node previous to mid
public ListNode findMidPrev(ListNode head, ListNode end) {
ListNode slowPrev = new ListNode(0);
slowPrev.next = head;
ListNode slow = head;
ListNode fast = head;
while (fast.next != end && fast != end && fast.next != null && fast != null) {
slowPrev = slowPrev.next;
slow = slow.next;
fast = fast.next.next;
}
return slowPrev;
}
}
For mid, your calculation would be better protected against overflow if it was this: int mid = start + (end-start)/2 ..Funny story, this was actually a bug in BST’s for a long time until someone found that it caused overflow. Hope this helps!
Elegant solution otherwise!
Approve for this algorithm: http://blog.flexdms.com/2014/03/sorted-list-to-height-balanced-binary.html
Hi. Can we put the input list as a member of first sortedListToBST function, and then pass it to second sortedListToBST function each time when calling it? If wo do it like this, and we move the pointer inside of sortedListToBST function, will this movement aware by caller? Thank you!
def build_from_sorted_list(cls, start_node, end_node=None):
if None == start_node:
return None
elif start_node is end_node:
return cls(start_node.value)
slow, fast = start_node, start_node
while (end_node is not slow.next) and (end_node is not fast.next) and (end_node is not fast.next.next):
slow = slow.next
fast = fast.next.next
node = cls(slow.value)
node.left = cls.build_from_sorted_list(start_node, slow)
node.right = cls.build_from_sorted_list(slow.next, end_node)
return node
recursive python version
elegant code, well done!
static keyword is not needed ….using only class variable shall work
yes but the whole point of implementing it differently from arrays is list does not permit random access and we are accessing actual node data sequentially in this program!!
Can we do the same without the static ListNode h
Can we pass it as a parameter to the method sortedListtoBST?
Yes, good idea!
Hi, can we not build a AVL/RB tree and balance them on the go?
Hi.
Do we need to use ceiling function to get the middle value?
If the list is 1 -> 2 -> 3 -> 4 -> 5 -> 6, then the solution you provide would first get 3 not 4. (Using 4 as root would generate a good-looking tree).