【C++贪心 DFS】2673. 使二叉树所有路径值相等的最小代价|1917

【C++贪心 DFS】2673. 使二叉树所有路径值相等的最小代价|1917

本文涉及知识点

C++贪心 反证法 决策包容性
C++DFS

LeetCode2673. 使二叉树所有路径值相等的最小代价

给你一个整数 n 表示一棵 满二叉树 里面节点的数目,节点编号从 1 到 n 。根节点编号为 1 ,树中每个非叶子节点 i 都有两个孩子,分别是左孩子 2 * i 和右孩子 2 * i + 1 。
树中每个节点都有一个值,用下标从 0 开始、长度为 n 的整数数组 cost 表示,其中 cost[i] 是第 i + 1 个节点的值。每次操作,你可以将树中 任意 节点的值 增加 1 。你可以执行操作 任意 次。
你的目标是让根到每一个 叶子结点 的路径值相等。请你返回 最少 需要执行增加操作多少次。
注意:
满二叉树 指的是一棵树,它满足树中除了叶子节点外每个节点都恰好有 2 个子节点,且所有叶子节点距离根节点距离相同。
路径值 指的是路径上所有节点的值之和。
示例 1:

在这里插入图片描述

输入:n = 7, cost = [1,5,2,2,3,3,1]
输出:6
解释:我们执行以下的增加操作:

  • 将节点 4 的值增加一次。
  • 将节点 3 的值增加三次。

将节点 7 的值增加两次。
从根到叶子的每一条路径值都为 9 。
总共增加次数为 1 + 3 + 2 = 6 。
这是最小的答案。
示例 2:

在这里插入图片描述

输入:n = 3, cost = [5,3,3]
输出:0
解释:两条路径已经有相等的路径值,所以不需要执行任何增加操作。
提示:
3 <= n <= 105
n + 1 是 2 的幂
cost.length == n
1 <= cost[i] <= 104

C++贪心

C++贪心

两轮DFS:
第一轮:后序DFS,求各子树最大路径和并保存,令整棵树路径和的最大值iMax。return 当前节点的值+ max(DFS1(左子树),DFS1(右子树));
第二轮: 前序DFS,当前节点增加:iMax - ( 当前节点的祖先节点和 + 本子树最大路径和)
性质一:由于只能增加,不能减少,所以最终路径和一定大于等于iMax。
性质二:路径和大于iMax,一定不是最优解。如果路径和大于iMax,说明所有路径都加了1,每条路径都减少一个增加的1。如果一条路径有多个节点可以减,减层次最小的(根节点层次最小,叶节点层次最大)。从层次小的节点开始减。这样可以避免某条路径被减少了两次,下面用反证法证明:
令路径p1的节点n1已经减1,给路径p2的节点n2减1的时候,p1再次减一。 → \rightarrow → n1,n2都是p1的祖先,n2包括p2,n1不包括。 → \rightarrow → n2的层次 < n1的层次。与假设矛盾。
结论一:最终路径和就是iMax。
如果某条路径需要增加,则在保证不让其他路径超过iMax的情况下,增加层次小的节点。这样可以让更多的路径增加。决策包容性
DFS2(cur,need)
cur += need - 当前子树最大路径值
DFS2(左子树,need-cur)
DFS2(右子树,need-cur)
为了方便计算,可以插入任意一个原始,这样下标就从1开始。

代码

核心代码

classSolution{public:intminIncrements(int N, vector<int>& cost){ cost.insert(cost.begin(),0); vector<int>maxs(N +1); function<int(int)> DFS1 =[&](int root){if(root > N){return0;}return maxs[root]= cost[root]+max(DFS1(root *2),DFS1(root *2+1));};constint iMax =DFS1(1);int ans =0; function<void(int,int)> DFS2 =[&](int root,int need){if(root > N){return;}constint iAdd = need - maxs[root]; ans += iAdd;DFS2(2* root, need - iAdd - cost[root]);DFS2(2* root +1, need - iAdd - cost[root]);};DFS2(1, iMax);return ans;}};

单元测试

int n; vector<int> cost;TEST_METHOD(TestMethod11){ n =7, cost ={1,5,2,2,3,3,1};auto res =Solution().minIncrements(n, cost);AssertEx(6, res);}TEST_METHOD(TestMethod12){ n =3, cost ={5,3,3};auto res =Solution().minIncrements(n, cost);AssertEx(0, res);}

优化(不需要DFS)

任何叶子节点必须和兄弟节点相等,否则这两条路径必定不等。
一,将所有叶子节点增加到和他的兄弟节点相等。
二,令当前树为cur,将各左叶子加到父节节点。删除所有叶子节点,形成新树next。cur符合题意 ⟺ \iff ⟺ next符合题意。
执行一二,树的最大层次会减少1。不断执行,直到树的层次为1,结束。
无需DFS,直接按节点编号从大到小执行。

classSolution{public:intminIncrements(int N, vector<int>& cost){ cost.insert(cost.begin(),0);int ans =0;for(int i = N; i >1; i-=2){constint iMin =min(cost[i], cost[i -1]);constint iMax =max(cost[i], cost[i -1]); ans += iMax - iMin; cost[i /2]+= iMax;}return ans;}};

扩展阅读

我想对大家说的话
工作中遇到的问题,可以按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。
学习算法:按章节学习《喜缺全书算法册》,大量的题目和测试用例,打包下载。重视操作
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛
失败+反思=成功 成功+反思=成功

视频课程

先学简单的课程,请移步ZEEKLOG学院,听白银讲师(也就是鄙人)的讲解。
https://edu.ZEEKLOG.net/course/detail/38771
如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.ZEEKLOG.net/lecturer/6176

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。

Read more

C++学习之旅【C++伸展树介绍以及红黑树的实现】

C++学习之旅【C++伸展树介绍以及红黑树的实现】

🔥承渊政道:个人主页 ❄️个人专栏: 《C语言基础语法知识》《数据结构与算法》 《C++知识内容》《Linux系统知识》 ✨逆境不吐心中苦,顺境不忘来时路!🎬 博主简介: 引言:前篇文章,小编已经介绍了关于C++AVL树的实现!相信大家应该有所收获!接下来我将带领大家继续深入学习C++的相关内容!本篇文章着重介绍关于C++伸展树介绍以及红黑树的实现!伸展树与红黑树是两类极具代表性的BBST,且在工程实践中各有不可替代的价值:伸展树摒弃了"严格平衡”的执念,通过“伸展”操作将最近访问的节点移至根节点,利用“局部性原理”优化频繁访问的场景,实现均摊O(logn)的时间复杂度,适合缓存、热点数据查询等场景;红黑树则通过给节点着色并遵守严格的颜色规则,确保树的最长路径不超过最短路径的两倍,以 “弱平衡” 换稳定的最坏O(logn)性能,是C++ STL 中 std::map、std:

By Ne0inhk
C++之unordered_set和unordered_map

C++之unordered_set和unordered_map

一、unordered系列关联式容器  在C++98中,STL提供了底层为红黑树结构的一系列关联式容器,在查询时效率可达到log_2 N,即最差情况下需要比较红黑树的高度次,当树中的节点非常多时,查询效率也不理想。最好 的查询是,进行很少的比较次数就能够将元素找到,因此在C++11中,STL又提供了4个 unordered系列的关联式容器,这四个容器与红黑树结构的关联式容器使用方式基本类似,只是 其底层结构不同 1.1 unordered_map  1.2 unordered_map的文档介绍 1. unordered_map是存储<key, value>键值对的关联式容器,其允许通过keys快速的索引到与 其对应的value。 2. 在unordered_map中,键值通常用于惟一地标识元素,而映射值是一个对象,其内容与此 键关联。键和映射值的类型可能不同。 3. 在内部, unordered_

By Ne0inhk

YOLOv8 C++部署实战:高性能推理引擎实现

YOLOv8 C++部署实战:高性能推理引擎实现 在智能安防摄像头实时检测行人、工业质检流水线上自动识别缺陷产品,或是自动驾驶车辆感知周围环境的瞬间——这些对响应速度要求极高的场景中,一个高效的视觉推理系统往往决定了整个项目的成败。而在这背后,YOLOv8 正成为越来越多工程师的首选目标检测模型。 但问题也随之而来:Python 训练出的模型虽然开发便捷,却难以满足生产环境中“低延迟、高吞吐”的硬性指标。解释器开销、GIL 锁限制、内存占用高等问题,在边缘设备或服务器集群上尤为突出。于是,将 YOLOv8 模型从 PyTorch 导出,并用 C++ 构建原生推理引擎,便成了通往真正落地的关键一步。 这不仅是一次语言层面的迁移,更是一场性能与可控性的全面升级。 为什么是 YOLOv8? YOLO 系列自诞生以来就以“单次前向传播完成检测”著称,尤其适合需要实时处理的应用。而 YOLOv8 作为 Ultralytics 推出的新一代版本,在保持高精度的同时进一步优化了架构设计和训练流程。 它支持多种任务类型—

By Ne0inhk