109. Convert Sorted List to Binary Search Tree

题目链接: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,可以通过两种方式进行。一是,找到插入位置,插入新节点,然后平衡节点,像第一个程序所示的那样。二是,先将元素排序,从中间节点把链表断开为两段,中间节点作为根节点的值,然后递归处理两段链表。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值