75.二叉树供暖问题|Marscode AI刷题

1.题目

问题描述

天气越来越冷了,村子里有留守老人缺少照顾,会在这个冬天里挨冻,小R想运用自己的知识帮帮他们。已知村庄里每户人家作为一个节点,这些节点可以组成一个二叉树。我们可以在二叉树的节点上供应暖炉,每个暖炉可以为该节点的父节点、自身及其子节点带来温暖。给定一棵二叉树,求使整个村庄都暖和起来至少需要供应多少个暖炉?

本题按层遍历顺序描述二叉树的节点情况。值为 1,代表存在一个节点,值为 0,代表不存在该节点。


测试样例

样例1:

输入:nodes = [1, 1, 0, 1, 1]

输出:1

样例2:

输入:nodes = [1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1]

输出:3

样例3:

输入:nodes = [1, 1, 0, 1, 1, 1, 1]

输出:2

2.思路

  • 构建二叉树
    • 输入是一个节点列表,其中 1 表示该节点存在,0 表示该节点不存在。我们需要根据这些节点信息,构建一棵二叉树。
    • 从列表中的第一个元素开始,根节点一定存在,然后逐级为每个节点分配左子节点和右子节点。使用队列来辅助构建树,逐个处理节点并为其分配子节点。
  • 深度优先搜索(DFS)
    • 我们的目标是计算每个子树中放置暖炉的最少数量。对于每个节点,可以有以下几种选择:
      • choose:在当前节点放置暖炉。
      • by_fa:当前节点的父节点已经放置暖炉,那么该节点可以不需要暖炉,或者根据情况放置暖炉。
      • by_children:当前节点的子节点放置暖炉时,当前节点可能也需要一个暖炉。
  • 状态转移
    • 对于每个节点,dfs 递归地计算其左右子树的状态值(即 choose, by_fa, by_children)。
    • 对于当前节点的左子树和右子树,分别考虑以下几种情况:
      • choose:当前节点放置暖炉时,左子树和右子树分别选择最优的方案(chooseby_fa)。
      • by_fa:当前节点的父节点已经放置暖炉,当前节点可以选择不放暖炉,或者根据子节点的状态决定是否需要放暖炉。
      • by_children:当前节点的子节点放置暖炉时,当前节点选择最优方案。
    • 然后返回这三种方案的最小值,作为当前节点的最优暖炉数量。
  • 返回结果
    • 从根节点开始递归计算,并返回根节点的最小暖炉数量。我们最终比较 chooseby_children 的值,选择最小值。

3.代码

from collections import deque # 导入双端队列,用于处理节点的层级遍历
from dataclasses import dataclass # 用于定义数据类
from typing import Optional # 用于表示可选类型(类型提示)

@dataclass
class TreeNode:
    # 定义二叉树节点的数据结构
    left: Optional['TreeNode'] = None
    right: Optional['TreeNode'] = None
def solution(nodes):
    # Please write your code here
    # 构建二叉树并找到至少需要多少个暖炉
    rt = TreeNode() # 创建根节点
    q1 = deque(nodes[1:]) # 从输入列表中获取节点信息(除去根节点)
    q2 = deque([rt]) # 创建一个队列,用于存储当前节点
    while q1: # 遍历节点
        u = q2.popleft() # 从队列中取出一个节点
        # 如果队列q1中还有元素,并且该元素为1,说明当前节点有左子节点
        if q1 and q1.popleft():
            v = TreeNode()
            u.left = v
            q2.append(v)
        # 如果队列q1中还有元素,并且该元素为1,说明当前节点有右子节点
        if q1 and q1.popleft():
            v = TreeNode()
            u.right = v
            q2.append(v)
    def dfs(node):
        # 深度优先遍历,并计算最少需要的暖炉数
        if node is None:
            return 10 ** 9, 0, 0 # 如果节点为空,返回很大的数,表示不需要暖炉
        # 递归遍历左子树和右子树
        l_choose, l_by_fa, l_by_children = dfs(node.left)
        r_choose, r_by_fa, r_by_children = dfs(node.right)
        # 选择在当前节点放暖炉时的情况
        choose = min(l_choose, l_by_fa) + min(r_choose, r_by_fa) + 1
        # 如果当前节点的父节点有暖炉,则计算父节点放暖炉的情况
        by_fa = min(l_choose, l_by_children) + min(r_choose, r_by_children)
        # 如果当前节点的子节点有暖炉,则计算子节点放暖炉的情况
        by_children = min(l_choose + r_by_children, r_choose + l_by_children, l_choose + r_choose)
        # 返回三种情况的结果
        return choose, by_fa, by_children
    # 调用dfs,返回的choose是从根节点开始的最少暖炉数
    choose, _, by_children = dfs(rt)

    # 返回最少需要的暖炉数
    return min(choose, by_children)

if __name__ == "__main__":
    #  You can add more test cases here
    print(solution([1, 1, 0, 1, 1]) == 1 )
    print(solution([1,0,1,1,0,1,0,1,0,1,0,0,1,1]) == 3 )
    print(solution([1,1,0,0,1,1,0,0,1,0,1,1,0,0,1]) == 3 )

  1. choose — 选择在当前节点放暖炉时的情况
  • 含义:这是当前节点本身选择放置暖炉时的最小暖炉数量。

  • 计算方式

    • l_choose 是左子树中选择放暖炉的最小数量。
    • l_by_fa 是左子树通过父节点来提供暖气的最小数量。
    • r_choose 是右子树中选择放暖炉的最小数量。
    • r_by_fa 是右子树通过父节点来提供暖气的最小数量。

    min(l_choose, l_by_fa)min(r_choose, r_by_fa) 分别表示在左子树和右子树中选择最优方案,不管是通过放暖炉在当前子树节点还是让父节点给子树提供暖气。然后再加上 1,表示当前节点本身也需要放一个暖炉来保证温暖。

  • 目的:为了让当前节点温暖,我们要从左子树和右子树的最优选择中选择最少的暖炉数量,并且加上当前节点的暖炉。


2. by_fa — 如果当前节点的父节点有暖炉,则计算父节点放暖炉的情况

by_fa = min(l_choose, l_by_children) + min(r_choose, r_by_children)

  • 含义:这是通过父节点提供暖气的最小暖炉数量。

  • 计算方式

    • l_choose 是左子树中放置暖炉的最小数量。
    • l_by_children 是左子树的子节点提供暖气的最小数量。
    • r_choose 是右子树中放置暖炉的最小数量。
    • r_by_children 是右子树的子节点提供暖气的最小数量。

    min(l_choose, l_by_children) 表示左子树的最优选择,不论是放暖炉在左子树节点,还是通过子节点提供暖气,右侧同理。

  • 目的:如果当前节点没有直接放暖炉的情况,那么它可能需要通过父节点提供暖气。by_fa 计算的是这样的一种最优情况,即父节点给左右子树分别提供暖气的最少暖炉数量。


3. by_children — 如果当前节点的子节点有暖炉,则计算子节点放暖炉的情况

by_children = min(l_choose + r_by_children, l_by_children + r_choose, l_choose + r_choose)
  • 含义:这是通过子节点提供暖气的最小暖炉数量。

  • 计算方式

    • l_choose 是左子树中放置暖炉的最小数量。
    • r_by_children 是右子树通过其子节点提供暖气的最小数量。
    • l_by_children 是左子树通过其子节点提供暖气的最小数量。
    • r_choose 是右子树中放置暖炉的最小数量。

    这里有三种情况:

    • l_choose + r_by_children:将暖炉放在左子树,并且右子树通过其子节点提供暖气。
    • l_by_children + r_choose:左子树通过其子节点提供暖气,右子树将暖炉放在其节点。
    • l_choose + r_choose:分别将暖炉放在左子树和右子树节点。
  • 目的:这是在考虑左右子树已经放置了暖炉的情况下,计算通过子节点(而非当前节点或父节点)来传递暖气的最优方式,得到最少的暖炉数量。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/970222.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CAS单点登录(第7版)20.用户界面

如有疑问,请看视频:CAS单点登录(第7版) 用户界面 概述 概述 对 CAS 用户界面 (UI) 进行品牌化涉及编辑 CSS 样式表以及一小部分相对简单的 HTML 包含文件,也称为视图。(可选&…

android 的抓包工具

charles 抓包工具 官网地址 nullCharles Web Debugging Proxy - Official Sitehttps://www.charlesproxy.com/使用手册一定记得看官网 SSL Certificates • Charles Web Debugging Proxy http请求: 1.启动代理: 2.设置设备端口 3.手机连接当前代理 …

关于视频去水印的一点尝试

一. 视频去水印的几种方法 1. 使用ffmpeg delogo滤镜 delogo 滤镜的原理是通过插值算法,用水印周围的像素填充水印的位置。 示例: ffmpeg -i input.mp4 -filter_complex "[0:v]delogox420:y920:w1070:h60" output.mp4 该命令表示通过滤镜…

预测技术在美团弹性伸缩场景的探索与应用

管理企业大规模服务的弹性伸缩场景中,往往会面临着两个挑战:第一个挑战是精准的负载预测,由于应用实例的启动需要一定预热时间,被动响应式伸缩会在一段时间内影响服务质量;第二个挑战是高效的资源分配,即在…

【含开题报告+文档+PPT+源码】基于Spring+Vue的拾光印记婚纱影楼管理系统

开题报告 本论文旨在探讨基于Spring和Vue框架的拾光印记婚纱影楼管理系统的设计与实现。该系统集成了用户注册登录、个人资料修改、婚庆资讯浏览、婚庆套餐查看、婚纱拍摄预约、婚纱浏览与租赁、客片查看以及在线客服等多项功能,为用户提供了一站式的婚纱影楼服务体…

ASP.NET Core 使用 FileStream 将 FileResult 文件发送到浏览器后删除该文件

FileStream 在向浏览器发送文件时节省了服务器内存和资源,但如果需要删除文件怎么办?本文介绍如何在发送文件后删除文件;用 C# 编写。 另请参阅:位图创建和下载 使用FileStream向浏览器发送数据效率更高,因为文件是从…

字节跳动后端二面

📍1. 数据库的事务性质,InnoDB是如何实现的? 数据库事务具有ACID特性,即原子性、一致性、隔离性和持久性。InnoDB通过以下机制实现这些特性: 🚀 实现细节: 原子性:通过undo log实…

【个人开发】cuda12.6安装vllm安装实践【内含踩坑经验】

1. 背景 vLLM是一个快速且易于使用的LLM推理和服务库。企业级应用比较普遍,尝试安装相关环境,尝试使用。 2. 环境 模块版本python3.10CUDA12.6torch2.5.1xformers0.0.28.post3flash_attn2.7.4vllm0.6.4.post1 2.1 安装flash_attn 具体选择什么版本&…

19.4.9 数据库方式操作Excel

版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。 本节所说的操作Excel操作是讲如何把Excel作为数据库来操作。 通过COM来操作Excel操作,请参看第21.2节 在第19.3.4节【…

2024-2025年主流的开源向量数据库推荐

以下是2024-2025年主流的开源向量数据库推荐,涵盖其核心功能和应用场景: 1. Milvus 特点:专为大规模向量搜索设计,支持万亿级向量数据集的毫秒级搜索,适用于图像搜索、聊天机器人、化学结构搜索等场景。采用无状态架…

vue项目使用vite和vue-router实现history路由模式空白页以及404问题

开发项目的时候,我们一般都会使用路由,但是使用hash路由还是history路由成为了两种选择,因为hash路由在url中带有#号,history没有带#号,看起来更加自然美观。但是hash速度更快而且更通用,history需要配置很…

AI编程01-生成前/后端接口对表-豆包(或Deepseek+WPS的AI

前言: 做过全栈的工程师知道,如果一个APP的项目分别是前端/后端两个团队开发的话,那么原型设计之后,通过接口文档进行开发对接是非常必要的。 传统的方法是,大家一起定义一个接口文档,然后,前端和后端的工程师进行为何,现在AI的时代,是不是通过AI能协助呢,显然可以…

切换git仓库远程地址

1、首先可以先查看一下当前git库的远程地址 【cd .git】 切换到git目录【cat config】查看【cd ../】 返回项目目录 2、 切换到目标远程git地址 【git remote rm origin】 删除现有远程仓库 【git remote add origin url】添加新远程仓库 【cat .git/config】验证是否切换成功…

mapbox 从入门到精通 - 目录

👨‍⚕️ 主页: gis分享者 👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍⚕️ 收录于专栏:mapbox 从入门到精通 文章目录 一、🍀总目录1.1 ☘️ mapbox基础1.2 ☘️…

前端包管理器的发展以及Npm、Yarn和Pnpm对比

在现代前端开发中,包管理器是不可或缺的核心工具。随着 JavaScript 生态的快速发展,开发者经历了从 npm 一统天下到 Yarn 挑战格局,再到 pnpm 创新突破的技术演进。这里将对三种主流包管理器(npm/Yarn/pnpm)进行全方位…

Qt QOpenGLWidget详解

1. 概述 QOpenGLWidget 是 Qt 框架中用于集成 OpenGL 渲染功能的类,它继承自 QWidget,允许开发者在 Qt 应用程序中轻松嵌入 OpenGL 图形。通过继承 QOpenGLWidget 并重写其虚函数(如 initializeGL()、resizeGL() 和 paintGL())&a…

Webpack包

黑马程序员视频地址: Node.js与Webpack-16.Webpack简介以及体验 前言: 本篇中部分标题后标有数字,代表学习顺序 ,同时也可以作为使用顺序参考 webpack包 基础认识 初步使用 下载webpack包和webpack-cli包 注意点: 1…

MySQL数据库入门到大蛇尚硅谷宋红康老师笔记 基础篇 part 10

第10章_创建和管理表 DDL:数据定义语言。CREATE \ALTER\ DROP \RENAME TRUNCATE DML:数据操作语言。INSERT \DELETE \UPDATE \SELECT(重中之重) DCL:数据控制语言。COMMIT \…

【DeepSeek】DeepSeek R1 本地windows部署(Ollama+Docker+OpenWebUI)

1、背景: 2025年1月,DeepSeek 正式发布 DeepSeek-R1 推理大模型。DeepSeek-R1 因其成本价格低廉,性能卓越,在 AI 行业引起了广泛关注。DeepSeek 提供了多种使用方式,满足不同用户的需求和场景。本地部署在数据安全、性…