题目描述(中等难度)
和 108 题 是一样的,都是给定一个升序序列,然后生成二分平衡查找树。区别在于 108 题给定的是数组,这里给的是链表。
解法一
大家先看一下 108 题 吧,算法的关键是取到中间的数据做为根节点。而这里链表的话,由于不支持随机访问,所以会麻烦些。最简单的思路就是我们把链表先用线性表存起来,然后题目就转换成 108 题了。
为了方便,把上一道题的数组参数改为List 。
import java.util.ArrayList;
class TreeNode{
int val;
TreeNode left;
TreeNode right;
TreeNode(int x){val=x;}
}
class ListNode{
int val;
ListNode next;
ListNode(int x){val=x;}
}
public class Convert_Sorted_List_to_Binary_Search_Tree {
public static TreeNode sortedListToBST(ListNode head) {
ArrayList<Integer>nums=new ArrayList<>();
//将链表用线性表存储起来,转换为108题
while(head!=null) {
nums.add(head.val);
head=head.next;
}
return sortedArrayToBST(nums);
}
public static TreeNode sortedArrayToBST(ArrayList<Integer>nums) {
return sortedArrayToBST(nums,0,nums.size());
}
private static TreeNode sortedArrayToBST(ArrayList<Integer>nums,int start,int end) {
if(start==end) return null;
int mid=(start+end)>>>1;
TreeNode root=new TreeNode(nums.get(mid));
root.left=sortedArrayToBST(nums,start,mid);
root.right=sortedArrayToBST(nums,mid+1,end);
return root;
}
public static void main(String args[]) {
ListNode head=new ListNode(-10);
ListNode p=head;
p.next=new ListNode(-3);
p=p.next;
p.next=new ListNode(0);
p=p.next;
p.next=new ListNode(5);
p=p.next;
p.next=new ListNode(9);
TreeNode ans=sortedListToBST(head);
System.out.println(ans.val);
}
}
时间复杂度:O(log(n))。
空间复杂度:数组进行辅助,O(n)。
解法二
有没有一种方案,不用数组的辅助呢?那么我们需要解决怎么得到 mid 的值的问题。
最直接的思路就是根据 start 和 end,求出 mid,然后从 head 遍历 mid - start 次,就到达了 mid 值。但最开始的 end,我们还得遍历一遍链表才能得到,总体来说就是太复杂了。
这里有一个求中点节点值的技巧,利用快慢指针。
快指针和慢指针同时从头部开始遍历,快指针每次走两步,慢指针每次走一步,当快指针走到链表尾部,此时慢指针就指向了中间位置。
除了求中点节点的值不一样,基本架构和 108 题 是一样的。
public class Convert_Sorted_List_to_Binary_Search_Tree2 {
public TreeNode sortedListToBST(ListNode head) {
return sortedArrayToBST(head,null);
}
private TreeNode sortedArrayToBST(ListNode head, ListNode tail) {
if(head==tail) return null;
ListNode fast=head;
ListNode slow=head;
while(fast!=tail &&fast.next!=tail) {
slow=slow.next;
fast=fast.next.next;
}
TreeNode root=new TreeNode(slow.val);
root.left=sortedArrayToBST(head,slow);
root.right=sortedArrayToBST(slow.next,tail);
return root;
}
}
时间复杂度:根据递归式可知,T(n) = 2 * T(n / 2 ) + n,O(nlog(n))。
空间复杂度:O(log(n))。
参考文献
1.https://zhuanlan.zhihu.com/p/74640795
2.https://leetcode.com/problems/convert-sorted-list-to-binary-search-tree/discuss/35476/Share-my-JAVA-solution-1ms-very-short-and-concise.