题目链接: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.

这道题的要求是将有序链表转化成高度平衡的二叉搜索树(BST)。

1. 利用sortedArrayToBST

先将链表转化为数组,再利用Convert Sorted Array to Binary Search Tree的sortedArrayToBST函数:

由于数组有序,因此相当于二叉搜索树的前序遍历。又由于要求二叉搜索树高度平衡,即左右子树高度相差小于等于1,所以取数组中间的数作为根节点,左边作为左子树,右边作为右子树,这样就可以构造出高度平衡的二叉搜索树了。

这样,思路就和Construct Binary Tree from Preorder and Inorder Traversal以及Construct Binary Tree from Inorder and Postorder Traversal差不多,都是递归构造左右子树即可。

时间复杂度:O(n)

空间复杂度:O(n)

 1 class Solution  2 { 3 public: 4     TreeNode *sortedListToBST(ListNode *head)  5     { 6         vector<int> vi; 7         for(ListNode *p = head; p != NULL; p = p -> next) 8             vi.push_back(p -> val); 9         return sortedArrayToBST(vi, 0, vi.size() - 1);10     }11 private:12     TreeNode *sortedArrayToBST(vector<int> &num, int l, int r)13     {14         if(l > r)15             return NULL;16         17         int m = (l + r) / 2;18         TreeNode *root = new TreeNode(num[m]);19         root -> left = sortedArrayToBST(num, l, m - 1);20         root -> right = sortedArrayToBST(num, m + 1, r);21         return root;22     }23 };

2. 递归直接转化

上面由于需要将链表存储到数组中,这需要申请O(n)的空间,这样子不好。应该考虑直接把有序链表转化成平衡的二叉搜索树。和Convert Sorted Array to Binary Search Tree同样的思路,先找到中间的节点作为根节点,然后左边作为左子树,右边作为右子树,递归构造左右子树即可。至于如何找到中间节点,这里利用快慢指针,慢指针s每次走一步,快指针f每次走两步,这样当f到达最后节点的时候,s就指向中间节点。这样,根节点找到了,然后分别递归左边节点生成左子树,递归右边节点生成右子树。

这样,思路就和Construct Binary Tree from Preorder and Inorder Traversal以及Construct Binary Tree from Inorder and Postorder Traversal差不多,都是递归构造左右子树即可。

时间复杂度:O(n)

空间复杂度:O(n)

 1 class Solution 2 { 3 public: 4     TreeNode *sortedListToBST(ListNode *head) 5     { 6         if(head == NULL || head -> next == NULL) 7             return head == NULL ? NULL : new TreeNode(head -> val); 8          9         // 找到中间节点10         ListNode *f = head -> next -> next, *s = head;11         while(f != NULL && f -> next != NULL)12         {13             f = f -> next -> next;14             s = s -> next;15         }16         17         ListNode *l = head, *m = s -> next, *r = m -> next;18         s -> next = NULL;19         20         TreeNode *root = new TreeNode(m -> val);21         root -> left = sortedListToBST(l);22         root -> right = sortedListToBST(r);23         24         return root;25     }26 };

上面代码在区分左右区域的时候,使左边的最后节点指向NULL,这样处理,就改变了原始链表的结构。下面是考虑添加tail标记,使其指向要构建二叉树区域的最后节点的下一位置,这样就可以在不改变原链表结构的情况下构建二叉搜索树了。

 1 class Solution 2 { 3 public: 4     TreeNode *sortedListToBST(ListNode *head) 5     { 6         return sortedListToBST(head, NULL); 7     } 8 private: 9     // 左闭右开,即head指向区间首节点,tail指向区间尾节点的next位置10     TreeNode *sortedListToBST(ListNode *head, ListNode *tail)11     {12         if(head == tail || head -> next == tail)13             return head == tail ? NULL : new TreeNode(head -> val);14         15         // 找到中间节点16         ListNode *f = head -> next -> next, *s = head;17         while(f != tail && f -> next != tail)18         {19             f = f -> next -> next;20             s = s -> next;21         }22         23         ListNode *lh = head, *lt = s -> next, *m = lt, 24                  *rh = m -> next, *rt = tail;25         TreeNode *root = new TreeNode(m -> val);26         root -> left = sortedListToBST(lh, lt);27         root -> right = sortedListToBST(rh, rt);28         return root;29     }30 };