Given a singly linked list where elements are sorted in ascending order, convert it to a height balanced BST.
第一思路就是先把鏈表元素取出來,存到數組裏,然後用把數組轉爲平衡BST的方法,結果內存溢出。看來這道題不允許O(n)的空間複雜度。
要用類似數組轉爲平衡BST的方法,就要不斷尋找中間元素。爲了減少空間複雜度,只能不斷遍歷鏈表,去尋找中間元素。這裏用快慢指針可以降低一些求中間元素的時間複雜度。
class Solution{
public:
TreeNode *sortedListToBST(ListNode *head) {
if (NULL == head) return NULL;
return convert(head, NULL);
}
ListNode *searchMid(ListNode *left, ListNode *right){
ListNode *slow = left, *fast = left;
while (fast != right && fast->next != right){
fast = fast->next->next;
slow = slow->next;
}
return slow;
}
TreeNode *convert(ListNode *head, ListNode *end){
if(NULL == head) return NULL;
if (head->next == end || head == end){
TreeNode *newNode = new TreeNode(head->val);
return newNode;
}
ListNode *mid = searchMid(head, end);
TreeNode *newNode = new TreeNode(mid->val);
newNode->left = convert(head,mid);
if(mid->next != end) newNode->right = convert(mid->next,end);
return newNode;
}
};
上邊的方法不多說了,比較容易寫出來。說實話這個方法中規中矩,時間複雜度比較高。一直想降低複雜度,但是沒有想到好方法。在網上看可很多,中遞歸的方法可以實現O(n)的時間複雜度。
利用中遞歸,自底向上的用中序構建這棵平衡BST。因爲要順序遍歷鏈表,因此遞歸中 的節點指針要不斷向後移動,所以要使用指針的引用,讓指針不斷變化。
class Solution{
public:
TreeNode *sortedListToBST(ListNode *head){
int len = calLen(head);
return convert(head, 0, len - 1);
}
int calLen(ListNode *head){
ListNode *tmp = head;
int len = 0;
while (tmp != NULL){
tmp = tmp->next;
len++;
}
return len;
}
TreeNode *convert(ListNode *&node, int left, int right){
if (left > right) return NULL;
int mid = (left + right) >> 1;
TreeNode *leftN = convert(node, left, mid - 1);
TreeNode *root = new TreeNode(node->val);
root->left = leftN;
node = node->next;
root->right = convert(node, mid + 1, right);
return root;
}
};
其實這道題的關鍵在於把握BST的性質,中序遍歷BST,就是升序排列樹的元素。那倒過來,順序遍歷升序鏈表,其實就是按中序自底向上生成平衡BST。
再就是從Run Time來看,兩種方法其實差不了多少,都在100多ms。雖然leetcode的運行時間有時不準,但這也一定程度上暴露了遞歸的弊病----慢.......