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