给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树。
本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。
示例:
给定的有序链表: [-10, -3, 0, 5, 9],
一个可能的答案是:[0, -3, 9, -10, null, 5], 它可以表示下面这个高度平衡二叉搜索树:
0
/ \
-3 9
/ /
-10 5
由题意,需要转换为高度平衡的BST,因此左右的高度差绝对值不超过1。**那么我们的根节点应该为有序链表的中位数。这里的中位数指的是,如果链表长度为奇数,那么就是中间的那个数,如果为偶数,中间的两个之一即可。**这样左子树和右子树的结点数量差最多为1,因此高度是平衡的。
二叉搜索树的左右子树也应该是二叉搜索树,因此,我们使用分治的方法,对左右子树的构建重复上面找中位数的过程。
找中位数的过程,**由于是链表,我们使用快慢指针来完成,快指针每次走两步,慢指针走一步,快指针走到头的时候,慢指针对应的即为中位数。**搜索的范围我们定位左开右闭[left,right),这样做的目的也是为了考虑到链表。最开始的时候搜索范围是[head,None),对于[left,right),假设找到的中位数是mid,那么root值即为mid的值,左子树的搜索范围即为[left,mid),右子树的搜索范围即为[mid.next,right)。
通过上面的递归分治过程,逐渐完成二叉树的建立。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def sortedListToBST(self, head: ListNode) -> TreeNode:
# 快慢指针找到搜索链表范围的中位数结点返回
def getmid(left:ListNode,right:ListNode) -> ListNode:
slow = left
fast = left
while fast != right and fast.next != right:
fast = fast.next.next
slow = slow.next
return slow
# 构建BST
def build(left:ListNode,right:ListNode) -> TreeNode:
if left == right:
return None
mid = getmid(left,right)
root = TreeNode(mid.val)
root.left = build(left,mid)
root.right = build(mid.next,right)
return root
# 返回构建BST之后的根节点
return build(head,None)
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
/**
* 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* sortedListToBST(ListNode* head) {
return build(head,nullptr);
}
ListNode* getmid(ListNode* left,ListNode* right){
ListNode* slow = left;
ListNode* fast = left;
while (fast != right && fast->next!=right){
fast = fast->next->next;
slow = slow->next;
}
return slow;
}
TreeNode* build(ListNode*left,ListNode*right){
if (left == right) return nullptr;
auto mid = getmid(left,right);
TreeNode* root = new TreeNode(mid->val);
root->left = build(left,mid);
root->right = build(mid->next,right);
return root;
}
};
上面的方法中,需要重复调用getmid函数,时间复杂度比较高。我们还可以利用另外一条性质进行优化,即二叉搜索树的中序遍历是递增的序列,因此链表即为二叉搜索树的中序遍历。
因此,我们跟上面的一致,同样找中位数作为root,但是不同的在于,我们先不赋值,先占位,即没有val的结点。完成构建平衡二叉树的同时中序遍历,使用链表中的值按顺序填充每个节点的值,这样就降低了时间复杂度。
在进行之前,需要遍历一遍链表,计算出一共有多少个节点,**将节点编号为[0,n),左开右闭,与上面方法一致,进行建树的过程。找到mid之后,左右子树就是[0,mid)和[mid+1,n)。**中序遍历的同时,中序遍历的第一个点即为最小值,即是head的值,然后head.next直到建树结束,中序遍历也结束了。
注意head应该是全局变量,在建树的时候它只变一次,从头走到尾,因此递归中,对于python,应该加nonlocal关键字限制;对于cpp,送入的head应该是对head指针的引用。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def sortedListToBST(self, head: ListNode) -> TreeNode:
# 求链表长度,有多少个节点
def getlength(head:ListNode) -> int:
cnt = 0
while head:
cnt += 1
head = head.next
return cnt
# 构建BST
def build(left:int,right:int) -> TreeNode:
# 左右相等,返回none
if left == right:
return None
# 中位数,分割左右子树
mid = (left+right)//2;
# root先占位
root = TreeNode()
# 标准中序遍历过程,先左子树,根节点,最后右子树
root.left = build(left,mid)
# head的值填写占位的值
nonlocal head
root.val = head.val
head = head.next
root.right = build(mid+1,right)
return root
# 返回构建BST之后的根节点
length = getlength(head)
return build(0,length)
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
/**
* 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* sortedListToBST(ListNode* head) {
auto n = getlength(head);
return build(0,n,head);
}
int getlength(ListNode* head){
int cnt = 0;
while (head){
cnt ++;
head = head->next;
}
return cnt;
}
TreeNode* build(int left,int right,ListNode*& head){
if (left == right) return nullptr;
int mid = (left+right)/2;
TreeNode* root = new TreeNode();
root->left = build(left,mid,head);
root->val = head->val;
head = head->next;
root->right = build(mid+1,right,head);
return root;
}
};