方法一:递归
给定列表中的中间元素将会作为二叉搜索树的根,该点左侧的所有元素递归的去构造左子树,同理右侧的元素构造右子树。这必然能够保证最后构造出的二叉搜索树是平衡的。
找出中间元素的地址将链表分为两半,然后递归构造二叉搜索树。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
private:
//寻找中间结点,并将链表分为两半,返回后一半首地址
ListNode* findMidandCutList(ListNode* head){
ListNode* slow=head;
ListNode* fast=head;
ListNode* pre=NULL;
while(fast!=NULL && fast->next!=NULL){
pre=slow;
slow=slow->next;
fast=fast->next->next;
}
if(pre)
pre->next=NULL;
return slow;
}
public:
TreeNode* sortedListToBST(ListNode* head) {
if(!head)
return NULL;
ListNode* mid=findMidandCutList(head);
TreeNode* res=new TreeNode(mid->val);
if(head==mid) //结束递归的条件
return res;
res->left=sortedListToBST(head);
res->right=sortedListToBST(mid->next);
return res;
}
};
时间复杂度:O(Nlog N)。
假设链表包含 N 个元素,对于传入递归函数的每个列表,我们需要计算它的中间元素。对于一个大小为 N 的列表,需要 N/2 步找到中间元素,也就是花费 O(N)的时间。我们对于原始数组的每一半都要同样的操作,看上去这是一个 O(N^2 ) 的算法,但仔细分析会发现比 O(N^2)
)更高效。
N/2+2N/4+4N/8+8*N/16…
空间复杂度:O(logN)。
对于一棵非平衡二叉树,可能需要 O(N) 的空间,但是问题描述中要求维护一棵平衡二叉树,所以保证树的高度上界为 O(logN),因此空间复杂度为O(logN)。