概述
108. 将有序数组转换为二叉搜索树
109. 有序链表转换二叉搜索树
延申题目:BST为什么是平衡的
1382. 将二叉搜索树变平衡
题目
108. 将有序数组转换为二叉搜索树
二分建树
直接二分建树就好
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* sortedArrayToBST(vector<int>& nums) {
if(nums.size()==0)return NULL;
return func(nums,0,nums.size()-1);
}
//功能:在给定的数组和上下标,构建一颗平衡的二叉树并放回
TreeNode* func(vector<int>& nums,int left,int right){
if(left>right)return NULL;
int mid=left+(right-left)/2;
// int mid=(right+left)/2;
TreeNode* root=new TreeNode(nums[mid]);
root->left=func(nums,left,mid-1);
root->right=func(nums,mid+1,right);
return root;
}
};
109. 有序链表转换二叉搜索树
暴力
沿用上一题的思路,我们把链表的值保存下来然后复用上一题的代码就行
class Solution:
def sortedListToBST(self, head: ListNode) -> TreeNode:
lst = []
p = head
while p:
lst.append(p.val)
p = p.next
def createTree(left,right):
if left > right:
return None
mid = (left+right)//2
root = TreeNode(lst[mid])
root.left = createTree(left,mid-1)
root.right = createTree(mid+1,right)
return root
return createTree(0,len(lst)-1)
时间复杂度
O
(
n
)
O(n)
O(n)
空间复杂度
O
(
n
)
O(n)
O(n)
快慢指针+递归
快慢指针走到链表的中间结点,然后链表中间结点一定是树根,接着对左右结点进行建树即可
需要注意的是这里是
[
s
t
a
r
t
,
e
n
d
)
[start,end)
[start,end)区间,然后我们对start.next = end
的情况进行特殊判断
class Solution:
def sortedListToBST(self, head: ListNode) -> TreeNode:
if not head:
return None
if not head.next:
return TreeNode(head.val)
# [start,end) => [head,None)
def createTree(start,end):
if start == end:
return None
# 特殊情况,只有一个结点
if start.next == end:
return TreeNode(start.val)
# find mid node
slow,fast = start,start
while fast != end and fast.next != end:
fast = fast.next.next
slow = slow.next
# create Tree
root = TreeNode(slow.val)
root.left = createTree(start,slow)
root.right = createTree(slow.next,end)
return root
return createTree(head,None)
和暴力法相比,不需要额外的存储空间,也不需要额外的遍历
时间复杂度
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn),通过主定理计算得出
T
(
n
)
=
2
⋅
T
(
n
/
2
)
+
O
(
n
)
T(n)=2⋅T(n/2)+O(n)
T(n)=2⋅T(n/2)+O(n)
空间复杂度
O
(
l
o
g
n
)
O(logn)
O(logn)
分治+中序遍历优化
来自官方题解
class Solution:
def sortedListToBST(self, head: ListNode) -> TreeNode:
def getLength(head: ListNode) -> int:
ret = 0
while head:
ret += 1
head = head.next
return ret
def buildTree(left: int, right: int) -> TreeNode:
if left > right:
return None
mid = (left + right + 1) // 2
root = TreeNode()
root.left = buildTree(left, mid - 1)
nonlocal head
root.val = head.val
head = head.next
root.right = buildTree(mid + 1, right)
return root
length = getLength(head)
return buildTree(0, length - 1)
c++的代码可能更好理解一点
class Solution {
public:
int getLength(ListNode* head) {
int ret = 0;
for (; head != nullptr; ++ret, head = head->next);
return ret;
}
TreeNode* buildTree(ListNode*& head, int left, int right) {
if (left > right) {
return nullptr;
}
int mid = (left + right + 1) / 2;
TreeNode* root = new TreeNode();
root->left = buildTree(head, left, mid - 1);
root->val = head->val;
head = head->next;
root->right = buildTree(head, mid + 1, right);
return root;
}
TreeNode* sortedListToBST(ListNode* head) {
int length = getLength(head);
return buildTree(head, 0, length - 1);
}
};
比较巧妙的思想,我们先新建节点,然后递归创建左右子树,按照代码的顺序,一定是碰到最左结点然后逐层返回上一级,此时的顺序刚好是链表的顺序,然后我们给root
结点赋值并移动head
即可
利用了BST中序遍历就是升序的性质
时间复杂度
O
(
n
)
O(n)
O(n),由主定理计算得出
T
(
n
)
=
2
∗
T
(
n
/
2
)
+
O
(
1
)
T(n) = 2*T(n/2) + O(1)
T(n)=2∗T(n/2)+O(1)
空间复杂度
O
(
l
o
g
n
)
O(logn)
O(logn)
1382. 将二叉搜索树变平衡
暴力二分
class Solution:
def balanceBST(self, root: TreeNode) -> TreeNode:
if not root:
return None
lst = []
def visited(root):
if not root:
return None
visited(root.left)
lst.append(root.val)
visited(root.right)
def createTree(lo,hi):
if lo>hi:
return None
mid = (hi+lo)//2
root = TreeNode(lst[mid])
root.left = createTree(lo,mid-1)
root.right = createTree(mid+1,hi)
return root
visited(root)
return createTree(0,len(lst)-1)
总结
三道题目,都是让我们转换成平衡的二叉树
主要是用到二分的思想