继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

图解精选 TOP 面试题 004 | LeetCode 108. 将有序数组转换为二叉搜索树

江不知
关注TA
已关注
手记 13
粉丝 2
获赞 16

作者:江不知
题解项目:LeetCode Notebook
编程拯救世界(ID: CodeWarrior_):专注于编程基础与服务端研发。

该系列题目取自 LeetCode 精选 TOP 面试题列表:https://leetcode-cn.com/problemset/top/

题目描述

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

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

示例:

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

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

      0
     / \
   -3   9
   /   /
 -10  5

解题思路

题目给出了一个升序排序的有序数组,要求我们转换为一棵高度平衡二叉搜索树

在此之前,我们先来回忆一下什么是二叉搜索树。

二叉搜索树

二叉搜索树(Binary Search Tree)是指一棵空树或具有如下性质的二叉树:

  1. 若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值
  2. 若任意节点的右子树不空,则右子树上所有节点的值均大于它的根节点的值
  3. 任意节点的左、右子树也分别为二叉搜索树
  4. 没有键值相等的节点

基于以上性质,我们可以得出一个二叉搜索树的特性:二叉搜索树的中序遍历结果为递增序列

那么现在题目给了我们一个递增序列,要求我们构造一棵二叉搜索树,就是要我们实现这一特性的逆过程

还记得什么是中序遍历吗?中序遍历的顺序为:根节点 →\to 左节点 →\to 右节点。这个遍历过程可以使用递归非常直观地进行表示。

如何构造树

构造一棵树的过程可以拆分成无数个这样的子问题:构造树的每个节点以及节点之间的关系。对于每个节点来说,都需要:

  1. 选取节点
  2. 构造该节点的左子树
  3. 构造该节点的右子树

因题目要求构造一棵「高度平衡」的树,所以我们在选取节点时选择数组的中点作为根节点,以此来保证平衡性。

以题目给出的 [-10,-3,0,5,9] 为例。

我们选取数组中点,即数字 0 作为根节点。此时,以 0 为分界点将数组分为左右两个部分,左侧为 [-10, -3],右侧为 [5, 9]。因该数组为升序排列的有序数组,所以左侧数组值均小于 0,可作为节点 0 的左子树;右侧数组值均大于 0,可作为节点 0 的右子树。

同上述步骤,将 [-10, -3][5, 9] 单独看作两棵树,从而继续为他们构造左右子树。

对于左侧数组 [-10, -3],我们选取 -3 作为根节点;对于右侧数组 [5, 9],选取 9 作为根节点。

最终构造结果如下:

递归设计

函数作用

通过上述解题过程我们可以明确该问题的子问题是:构造树的每个节点以及该节点的左右子树。因此,递归函数的作用很明显:

  1. 选取要构造关系的节点并创建它
  2. 构造该节点的左子树
  3. 构造该节点的右子树

函数的输入为递增数组,函数的返回为完成构造的节点

何时结束

当输入的递增数组为空时,只能构成一棵空树,此时返回空节点。

何时调用

当构造节点的左右子树时,对递增数组进行拆分并进行递归调用。

具体实现

Python

# 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
        node = TreeNode(nums[mid])

        # 左侧数组作为左子树
        left = nums[:mid]
        right = nums[mid+1:]

        # 递归调用
        node.left = self.sortedArrayToBST(left)
        node.right = self.sortedArrayToBST(right)

        return node

Go

/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func sortedArrayToBST(nums []int) *TreeNode {
    if len(nums) == 0 {
        return nil
    }

    mid := len(nums) / 2
    
    left := nums[:mid]
    right := nums[mid+1:]

    node := &TreeNode{nums[mid], sortedArrayToBST(left), sortedArrayToBST(right)}

    return node
}

复杂度

  • 时间复杂度:O(n)O(n)O(n)
  • 空间复杂度:O(log(n))O(log(n))O(log(n))

总结

  • 本题考察点:二叉搜索树、树的构造、中序遍历
  • 二叉搜索树左子树上所有节点的值均小于它的根节点的值,右子树上所有节点的值均大于它的根节点的值
  • 二叉搜索树的中序遍历结果为递增序列

往期回顾

推荐阅读

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP