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