https://oj.leetcode.com/problems/convert-sorted-list-to-binary-search-tree/
Given a singly linked list where elements are sorted in ascending order, convert it to a height balanced BST.
解题思路:
首先,这题与 Convert Sorted Array to Binary Search Tree 很类似,可以用递归的方法来解。难度在于,List和Array的不同,不能直接获取节点的下标,以及计算这段list的中点,也不能比较他们start和end下标的大小,以便在start>end的时候合理退出。所以需要取得midNode,同时还要获得midNode的前一个节点。每次递归进入方法的时候,需要对于只有一个节点,和只有两个节点的情况,分别处理,否则就会出错。
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; next = null; } * } */ /** * Definition for binary tree * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ public class Solution { public TreeNode sortedListToBST(ListNode head) { if(head == null){ return null; } ListNode end = head; while(end.next != null){ end = end.next; } return sortedListToBSTHelper(head, end); } public TreeNode sortedListToBSTHelper(ListNode head, ListNode end){ //nodeNum == 0,只有一个节点的情况 if(head == end){ return new TreeNode(head.val); } int nodeNum = 0; ListNode tempNode = head; while(tempNode != end){ tempNode = tempNode.next; nodeNum++; } //nodeNum == 1,只有两个节点的情况 if(nodeNum == 1){ TreeNode root = new TreeNode(head.val); root.right = sortedListToBSTHelper(head.next, end); return root; } //nodeNum > 2的情况 TreeNode preMidNode = head; for(int i = 0; i < nodeNum / 2 - 1; i++){ preMidNode = preMidNode.next; } ListNode midNode = preMidNode.next; TreeNode root = new TreeNode(midNode.val); root.left = sortedListToBSTHelper(head, preMidNode); root.right = sortedListToBSTHelper(midNode.next, end); return root; } }
后来在网上看到一个左闭右开的方法,类似于二分查找,在 Find Minimum in Rotated Sorted Array 和 Search Insert Position 问题里提到过这个问题。那么右边界只要取midNode就可以了,不必取得他的钱一个节点。同时,调用递归方法的时候,也必须为sortedListToBSTHelper(head, null);而不能是sortedListToBSTHelper(head, end)。
还要注意,计算列表节点数量的方法也发生了变化,因为end已经是一个开放的区间。
这样避免了preMidNode节点和start的判断问题,代码简单了。
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; next = null; } * } */ /** * Definition for binary tree * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ public class Solution { public TreeNode sortedListToBST(ListNode head) { if(head == null){ return null; } return sortedListToBSTHelper(head, null); } public TreeNode sortedListToBSTHelper(ListNode head, ListNode end){ if(head == end){ return null; } //nodeNum == 0,只有一个节点的情况 if(head.next == end){ return new TreeNode(head.val); } int nodeNum = 0; ListNode tempNode = head; while(tempNode.next != end){ tempNode = tempNode.next; nodeNum++; } //nodeNum == 1,只有两个节点的情况,可以省略 //左闭右开的方法下面已经涵盖 // if(nodeNum == 1){ // TreeNode root = new TreeNode(head.val); // root.right = sortedListToBSTHelper(head.next, end); // return root; // } //nodeNum > 2的情况 ListNode midNode = head; for(int i = 0; i < nodeNum / 2; i++){ midNode = midNode.next; } TreeNode root = new TreeNode(midNode.val); root.left = sortedListToBSTHelper(head, midNode); root.right = sortedListToBSTHelper(midNode.next, end); return root; } }
把取得中间节点作为一个方法拿出来,refactor代码。
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; next = null; } * } */ /** * Definition for binary tree * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ public class Solution { public TreeNode sortedListToBST(ListNode head) { if(head == null){ return null; } return sortedListToBSTHelper(head, null); } public TreeNode sortedListToBSTHelper(ListNode head, ListNode end){ if(head == end){ return null; } //nodeNum == 0,只有一个节点的情况 if(head.next == end){ return new TreeNode(head.val); } ListNode midNode = getMidNode(head, end); TreeNode root = new TreeNode(midNode.val); root.left = sortedListToBSTHelper(head, midNode); root.right = sortedListToBSTHelper(midNode.next, end); return root; } public ListNode getMidNode(ListNode head, ListNode end){ int nodeNum = 0; ListNode tempNode = head; while(tempNode.next != end){ tempNode = tempNode.next; nodeNum++; } ListNode midNode = head; for(int i = 0; i < nodeNum / 2; i++){ midNode = midNode.next; } return midNode; } }
利用快慢指针的方法,找一个链表中点,可以写成下面的方法。
public ListNode getMidNode(ListNode head, ListNode end){ ListNode quickNode = head; ListNode slowNode = head; while(quickNode != end && quickNode.next != end){ quickNode = quickNode.next.next; slowNode = slowNode.next; } return slowNode; } }
或者下面的形式,更容易理解一些。
public ListNode getMidNode(ListNode head, ListNode end){ ListNode quickNode = head; ListNode slowNode = head; while(quickNode.next != end){ quickNode = quickNode.next; if(quickNode.next != end){ quickNode = quickNode.next; slowNode = slowNode.next; } } return slowNode; } }
同样下面的方法也是对的,想想为什么循环终止的条件,quickNode != end 和 quickNode.next != end都可以?
public ListNode getMidNode(ListNode head, ListNode end){ ListNode quickNode = head; ListNode slowNode = head; while(quickNode != end){ quickNode = quickNode.next; if(quickNode != end){ quickNode = quickNode.next; slowNode = slowNode.next; } } return slowNode; }
因为1-2-3-4这样的数列,下面两种BST都是平衡的。
3 2
/ \ / \
2 4 1 3
/ \
1 4
update 2015/05/16:
二刷
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */ /** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ public class Solution { public TreeNode sortedListToBST(ListNode head) { return sortedListToBSTHelper(head, null); } public TreeNode sortedListToBSTHelper(ListNode head, ListNode tail) { if(head == tail) { return null; } ListNode midNode = getMidNode(head, tail); TreeNode root = new TreeNode(midNode.val); root.left = sortedListToBSTHelper(head, midNode); root.right = sortedListToBSTHelper(midNode.next, tail); return root; } public ListNode getMidNode(ListNode head, ListNode tail) { ListNode fast = head; ListNode slow = head; while(fast != tail) { fast = fast.next; if(fast != tail) { fast = fast.next; slow = slow.next; } } return slow; } }