有序数组(或链表)转成二叉搜索树的问题

一、【LeetCode 108】有序数组转成二叉搜索树

1.题目描述

将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。

本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。

示例:

给定有序数组: [-10,-3,0,5,9],

一个可能的答案是:[0,-3,9,-10,null,5],它可以表示下面这个高度平衡二叉搜索树:

      0
     / \
   -3   9
   /   /
 -10  5

2.解题思路

(1)由二叉树的相关知识可知:

  • 二叉树的三种深度优先遍历中的任何一种(前序/中序/后序)都无法唯一确定一个二叉树;
  • 只有(中序+前序)或(中序+后序)才能唯一确定一个二叉树。

(2)所以本题只给了一个有序数组,相当于二叉搜索树的中序遍历,没法确定一个唯一的结果,虽然添加了附加条件(要求左右子树的高度差不超过1),仍有多种情况。
(3)故根据此附加条件,最简便的方法就是取数组的中间值为根节点,将数组分成近乎相等的两个部分(若数组的个数是奇数个,则左右部分刚好相等;若数组个数是偶数个,左子树和右子树相差为1),然后递归用同样的方法去重建左子树和右子树,最后返回根节点即可。

3.代码

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def sortedArrayToBST(self, nums: List[int]) -> TreeNode:
        if not nums:
            return None
        mid = len(nums) // 2
        root = TreeNode(nums[mid])
        root.left = self.sortedArrayToBST(nums[:mid])
        root.right = self.sortedArrayToBST(nums[mid+1:])
        return root

二、【LeetCode 109】有序链表转换为二叉搜索树

1.题目描述

给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树。

本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。

示例:

给定的有序链表: [-10, -3, 0, 5, 9],

一个可能的答案是:[0, -3, 9, -10, null, 5], 它可以表示下面这个高度平衡二叉搜索树:

      0
     / \
   -3   9
   /   /
 -10  5

2.解题思路

有序链表找中间节点使用快慢指针,fast指针比slow指针多走一步,fast指针走到尾时,slow指针刚好指向近似中间节点。找到中间节点就可以利用类似于【有序数组转换二叉搜索树】的方法来进行递归了。

3.代码

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:     
    def sortedListToBST(self, head: ListNode) -> TreeNode:
        return self.helper(head, None)

    def findmid(self, head, tail):
        slow = head
        fast = head
        while fast != tail and fast.next != tail:
            slow = slow.next
            fast = fast.next.next
        return slow

    def helper(self, head, tail):
        if head == tail:
            return
        node = self.findmid(head, tail)
        root = TreeNode(node.val)
        root.left = self.helper(head, node)
        root.right = self.helper(node.next, tail)
        return root

三、补充总结

1.有序数组找中点

数组找中点很简便,计算出数组的长度,直接定位即可:mid = len(nums) // 2

2.有序链表找中点

由于链表不能直接定位到中间节点,获取整个链表的长度需要从头到尾遍历一遍。

  • 有一种方法是遍历整个链表,将链表每个节点的值保存到数组中,再通过数组的直接定位获取中间节点的值。————这种方法虽然可行,但是不太符合链表的形式。若需要改变节点,而不是节点的值,整个方法就不管用了!
  • 最经典的还是快慢指针,最初 slow 和 fast 同在起始位置,slow 指针每次走一步,fast 指针每次走两步,当 fast 走到末尾时,slow 恰好指向中间节点!
    while fast != None and fast.next != None:while循环里表示了两种情况:
    (1)当链表节点数为偶数时,fast 指向空时,slow 恰好指向中间(这种情况的循环条件就是 fast != None
    (2)当链表节点数为奇数时,fast 刚好走到末尾,slow 恰好指向中间节点(这种情况的循环条件就是 fast.next != None
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值