Given a singly linked list where elements are sorted in ascending order, convert it to a height balanced BST.
将链表转换为平衡二叉搜索树。
平衡的要点是取到中点的数据,搜索树的要点是左小右大(排好序的链表已经帮我们实现了这一点)
相比较数组,链表需要寻找开始和末尾节点。
并且在划分区间的时候,需要找到划分节点的prev节点。
这样一般是使用prev=start,temp=prev->next;并成功找到目的temp节点,prev节点即为所需。
但是需要注意start=end的时候需要特判,这时候prev和next都应当=NULL
class Solution {
public:
TreeNode* sortedListToBST(ListNode* head) {
ListNode* temp=head;
while(temp && temp->next) temp=temp->next;
return generate(head,temp);
}
//时间复杂度T(n)=2T(n/2)+n 即O(nlogN)
TreeNode* generate(ListNode* start,ListNode* end){
int n=1;
if(!start || !end) return NULL;
//边界条件
ListNode* temp=start;
for(;temp && temp!=end;temp=temp->next,n++);
if(temp!=end) return NULL;
//获取中值
//需要获取到中值的prev和next
ListNode *prev,*next;
//仅有一个值
if(start==end){
prev=NULL;next=NULL;
temp=end;
}
else{
prev=start;temp=prev->next;
for(int i=1;temp && i<n/2;i++,temp=temp->next,prev=prev->next);
next=temp?temp->next:NULL;
}
printf("val %d\n",temp->val);
//获取到temp为中点,prev为其前缀,next为后缀
TreeNode* node=new TreeNode(temp->val);
node->left=generate(start,prev);
node->right=generate(next,end);
return node;
}
};
寻找中位数和之后写的不是很优雅。
然后在讨论区看到了比较好的思路:
引出这个思路,我们可以考虑一下:如何在O(n)的时间内找到一个链表的中位数?
答案:使用双指针,一个fast每次走两步,另一个slow每次走一步。
和之前链表题里面一道追赶的题目颇为类似;
// fast/slow pointer to find the midpoint
auto slow = head;
auto fast = head;
auto pre = head;
while(fast && fast->next) {
pre = slow;
slow = slow->next;
fast = fast->next->next;
}
pre->next = 0; // break two halves
// slow is the midpoint, use as root
TreeNode* root = new TreeNode(slow->val);
root->left = sortedListToBST(head);
root->right = sortedListToBST(slow->next);
另外,有一种O(n)的做法
可以通过模拟中序遍历的方法,先递归出左子树,接着将左子树的节点赋值给当前node,再递归求出节点的右子树。
这种方法不太常规,因为一般都是已知了一个节点之后去递归生成两个孩子节点。
//时间O(n) 空间O(logN)
TreeNode* sortedToBST(ListNode* &head,int start,int end){
if(start>end) return NULL;
int mid=start+(end-start)/2;//获取中间下标
TreeNode* left=sortedToBST(head,start,mid-1);
TreeNode* parent=new TreeNode(head->val);
parent->left=left;
//等于使用中序遍历,
head=head->next;
parent->right=sortedToBST(head,mid+1,end);
return parent;
}