leetcode面试打卡笔记(2) datawhale

算法打卡

二叉树的表示方式

使用数组来表示二叉树是一种常见的方法,尤其是对于完全二叉树或满二叉树来说,这种表示方法非常高效和直观。在这种表示法中,二叉树的每个节点都对应数组中的一个位置,数组的索引用于表示节点之间的父子关系。

基本规则

  1. 根节点位于数组的第一个位置,即索引 0
  2. 对于数组中任意位置 i 的元素,其左子节点的位置为 2*i + 1,右子节点的位置为 2*i + 2
  3. 同样,对于数组中任意位置 i 的元素,其父节点的位置为 (i-1) / 2(向下取整)。

例子

考虑一个简单的二叉树如下:

    1
   / \
  2   3
 / \
4   5

这棵树可以用数组 [1, 2, 3, 4, 5] 来表示。具体对应关系如下:

  • 根节点 1 在数组位置 0
  • 1 的左子节点 2 在位置 2*0+1 = 1
  • 1 的右子节点 3 在位置 2*0+2 = 2
  • 2 的左子节点 4 在位置 2*1+1 = 3
  • 2 的右子节点 5 在位置 2*1+2 = 4

完全二叉树与非完全二叉树

这种表示方法对于完全二叉树是最有效的,因为在完全二叉树中,不存在跳过的数组位置。对于非完全二叉树,这种方法也可以使用,但可能会导致数组中存在一些未使用的位置(用一些特殊值表示,如null),这些位置代表了虚拟的空节点,以保持父子节点间正确的位置关系。

例如,对于一个非完全二叉树:

    1
   /
  2   
 / \
3   4

这棵树可以用数组 [1, 2, null, 3, 4] 来表示,其中 null 位置代表原本应该是第一个节点右子节点的位置,但在这个树中不存在。

使用数组来表示二叉树时,可以有效地访问和修改节点,尤其是在实现某些数据结构如二叉堆时非常有用。

二叉树遍历基本概念

假设有二叉树的两种遍历结果 [3,9,20,15,7](前序遍历结果)和 [9,3,15,20,7](中序遍历结果)做的那样。

理解前序和中序遍历

首先,想象一下你有一个箱子里装满了玩具,你要按照一定的规则来拿出这些玩具。

  • 前序遍历就像是先拿出最上面的玩具(我们称它为“根”玩具),然后从左边开始拿出下面的玩具,一直到你不能再向左拿时,你再开始从右边拿。
  • 中序遍历则是你先从最左边开始拿玩具,直到你不能再拿(到达最左边的玩具),然后回到上一个能向右拿的玩具,再继续向右拿。

如何构造二叉树

  1. 找到根节点:在前序遍历中,第一个数字总是“根”玩具,也就是整个树的最顶部。在我们的例子中,3是根节点。

  2. 分割点:在中序遍历中找到这个根节点(3),它会告诉我们哪些数字在它的左边(9),哪些在右边(15, 20, 7)。这意味着左边的都在左子树中,右边的都在右子树中。

  3. 构造左子树和右子树:用相同的方法,我们用左边的数字(9)和右边的数字(15, 20, 7)分别构造左子树和右子树。在我们的例子中,9就直接成为了左子节点,因为它没有其他的左边或右边的数字了。对于右边的数字,20成为右子树的根节点,157分别成为它的左子节点和右子节点。

  4. 重复步骤:对于每个子树,我们重复这个过程,直到所有的数字都被用完。

结果

通过这个方法,我们就可以构建出一个二叉树。最后的结构是这样的:

    3
   / \
  9  20
    /  \
   15   7
  • 3是根节点。
  • 93的左子节点。
  • 203的右子节点,而157分别是20的左子节点和右子节点。

打卡题目

根据前序 中序遍历结果推断出二叉树结构
描述:给定一棵二叉树的前序遍历结果 preorder 和中序遍历结果 inorder。
要求:构造出该二叉树并返回其根节点。

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right


def buildTree(preorder, inorder):
    if not preorder or not inorder:
        return None

    # 前序遍历的第一个值是根节点
    root_val = preorder[0]
    root = TreeNode(root_val)

    # 在中序遍历中找到根节点的位置,以此来分割左子树和右子树
    index = inorder.index(root_val)

    # 递归构造左子树和右子树
    root.left = buildTree(preorder[1:index + 1], inorder[:index])
    root.right = buildTree(preorder[index + 1:], inorder[index + 1:])

    return root


# 用于展示二叉树的辅助函数
def serialize(root):
    """Encodes a tree to a single string."""
    if not root:
        return "null,"

    left_serialized = serialize(root.left)
    right_serialized = serialize(root.right)

    return str(root.val) + "," + left_serialized + right_serialized


# 测试数据
preorder = [3, 9, 20, 15, 7]
inorder = [9, 3, 15, 20, 7]

# 构造二叉树并序列化以便显示结果
root = buildTree(preorder, inorder)
prialanced(root.left) and self.isBalanced(root.right) 

判断二叉搜索树
描述:给定一个二叉树的根节点 root。
要求:判断其是否是一个有效的二叉搜索树。
说明:
二叉搜索树特征:
节点的左子树只包含小于当前节点的数。
节点的右子树只包含大于当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right


def isValidBST(root):
    def validate(node, low=-float('inf'), high=float('inf')):
        # 空节点默认是有效的
        if not node:
            return True
        # 当前节点的值必须在有效范围内
        if not (low < node.val < high):
            return False
        # 递归检查左子树和右子树
        return (validate(node.left, low, node.val) and
                validate(node.right, node.val, high))

    return validate(root)


# 构造示例二叉树 [2,1,3]
root = TreeNode(2)
root.left = TreeNode(1)
root.right = TreeNode(3)

# 检查是否是有效的二叉搜索树
isValidBST(root)

计算平衡二叉树 --> 左右子树高度差相差1
描述:给定一个二叉树的根节点 root。
要求:判断该二叉树是否是高度平衡的二叉树。
说明:
高度平衡二叉树:二叉树中每个节点的左右两个子树的高度差的绝对值不超过

class Solution:
    def isBalanced(self, root: Optional[TreeNode]) -> bool:
        def height(root):
            # 遍历到末尾返回0
            if not root:
                return 0
            # 递归获取高度
            return max( height(root.left) , height(root.right) ) + 1
        if not root:
            return True
        # 递归计算所有的节点都是平衡二叉树 
        return abs(height(root.left) - height(root.right))<=1 and self.isBalanced(root.left) and self.isBalanced(root.right) 

路径总和2

给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。

叶子节点 是指没有子节点的节点。

    class Solution:
    def pathSum(self, root: TreeNode, targetSum: int) -> List[List[int]]:
        ret = list()
        path = list()
        
        def dfs(root: TreeNode, targetSum: int):
            if not root:
                return
            path.append(root.val)
            targetSum -= root.val
            if not root.left and not root.right and targetSum == 0:
                ret.append(path[:])
            dfs(root.left, targetSum)
            dfs(root.right, targetSum)
            path.pop()
  • 20
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值