题目链接:https://leetcode.com/problems/convert-sorted-list-to-binary-search-tree/description/
一开始没有注意到连接中的元素已经有序了这个条件,按照链表中元素的顺序,一个个的往平衡二叉树中插入节点,结果导致运行时间超时。下面的代码是就是这种思路。
class Solution(object):
def getHeight(self,root):#求以root为根的树的高度
if root==None:
return 0
else:
leftHeight=self.getHeight(root.left)
rightHeight=self.getHeight(root.right)
return leftHeight+1 if leftHeight>rightHeight else rightHeight+1
#得到左右子树的高度差,即平衡因子
def getBalance(self,root):
return self.getHeight(root.left)-self.getHeight(root.right)
def leftRotation(self,root):#左旋转
temp=root.right
root.right=temp.left
temp.left=root
return temp
def rightRotatioin(self,root):#右旋转
temp=root.left
root.left=temp.right
temp.right=root
return temp
def insertTreeNode(self,value,root):#先插入在旋转
if root==None:#找到插入位置
root=TreeNode(value)#建立新节点,并返回
return root
elif root.val>value:#“根节点”的值较大,到左子树上寻找插入位置
root.left=self.insertTreeNode(value,root.left)
if abs(self.getBalance(root))>1:#该节点的平衡因子大于1,则需要旋转调整
#判断旋转的类型。因为在该节点的左子树上插入的新节点,所以左子树上一定从下往上多了一层
#接着判断到底插入位置是在该节点的左子树的左子树还是该节点的左子树的右子树上
#如果该节点的左子树的平衡因子等于1,说明插入位置在该节点的左子树的左子树上,才能使该节点的左子树的左子树的高度加1
#进而使(该节点的左子树的)左子树的高度减(该节点的左子树的)右子树的高度差为1;
#如果插入位置在(该节点的左子树的)右子树上,那么(该节点的左子树的)的左子树的高度不变,
#这将导致该节点的左子树的平衡因子为-1,这时是LR(先左转后右转)旋转
#其他情况相似
if self.getBalance(root.left)==1:
return self.rightRotatioin(root)
elif self.getBalance(root.left)==-1:
root.left=self.leftRotation(root.left)
return self.rightRotatioin(root)
else:#root.val<=value,到右子树上寻找插入位置
root.right=self.insertTreeNode(value,root.right)
print self.getBalance(root)
if abs(self.getBalance(root))>1:
if self.getBalance(root.right)==1:
root.right=self.rightRotatioin(root.right)#先使该节点的右节点右旋,
return self.leftRotation(root)#再将该节点左旋
elif self.getBalance(root.right)==-1:
return self.leftRotation(root)
return root
def sortedListToBST(self, head):
"""
:type head: ListNode
:rtype: TreeNode
"""
p,root=head,None
while p:
#依次插入链表中的值
root=self.insertTreeNode(p.val,root)
p=p.next
return root
运行时间超时后,才想起来链表中的元素是升序排列的,看到讨论区里的快,慢指针,突然想起来可以把每一段链表从中间断开为两段链表,把中间节点的值作为相应的”根节点”,然后递归处理左右两段链表。基于这种想法,算法如下
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def sortedListToBST(self, head):
"""
:type head: ListNode
:rtype: TreeNode
"""
if head==None:#递归结束条件
return head
if head.next==None:#递归结束条件
temp=TreeNode(head.val)
return temp
now,slow,fast=None,head,head
while fast and fast.next:
now=slow
slow=slow.next
fast=fast.next.next
#经过上面的循环,中间的节点位置为slow,把该节点作为“根节点”
now.next=None#断开为两段链表
root=TreeNode(slow.val)#建立根节点
#递归的进行处理
root.left=self.sortedListToBST(head)#对左半部分的链表递归,所建立的树的节点都在该“根节点”的左子树上
root.right=self.sortedListToBST(slow.next)#对右半部份的链表递归,同理所建的节点都在右子树
return root
在复习AVL(self-balancing binary search tree)的过程中,突然有新收获。
1、对于有指针的操作,好像是大部分都是关于指针断开,和如何连接指针的操作。在第一种算法中,找到插入位置,插入新节点,然后再平衡,好像不太明显。再第二种算法中,就是建立新节点,并连接指针的过程,而建立新节点的时候,节点之间是相互断开的,之后的递归返回的过程,就是把这这些游离的节点连接的过程。这是自己的新体会。
2、建立一棵AVL,可以通过两种方式进行。一是,找到插入位置,插入新节点,然后平衡节点,像第一个程序所示的那样。二是,先将元素排序,从中间节点把链表断开为两段,中间节点作为根节点的值,然后递归处理两段链表。