Leetcode每日一题(困难):834. 树中距离之和(2023.7.16 C++)

目录

834. 树中距离之和

题目描述:

实现代码与解析:

DFS

原理思路:


834. 树中距离之和

题目描述:

        给定一个无向、连通的树。树中有 n 个标记为 0...n-1 的节点以及 n-1 条边 。

给定整数 n 和数组 edges , edges[i] = [ai, bi]表示树中的节点 ai 和 bi 之间有一条边。

返回长度为 n 的数组 answer ,其中 answer[i] 是树中第 i 个节点与所有其他节点之间的距离之和。

示例 1:

输入: n = 6, edges = [[0,1],[0,2],[2,3],[2,4],[2,5]]
输出: [8,12,6,10,10,10]
解释: 树如图所示。
我们可以计算出 dist(0,1) + dist(0,2) + dist(0,3) + dist(0,4) + dist(0,5) 
也就是 1 + 1 + 2 + 2 + 2 = 8。 因此,answer[0] = 8,以此类推。

示例 2:

输入: n = 1, edges = []
输出: [0]

示例 3:

输入: n = 2, edges = [[1,0]]
输出: [1,1]

实现代码与解析:

DFS

class Solution {
public:int nodeNum[300010]; // 结点 i 所在子树的结点个数int distSum[300010]; // 第一次dfs:结点 i 所在的子树的结点到 i 距离和。// 第二次dfs2:结果,结点 i 到所有节点的距离和。int h[300010], e[300010], ne[300010], idx; // 邻接表// 邻接表加边void add(int a, int b){e[idx] = b, ne[idx] = h[a], h[a] = idx++;}// 后序遍历void dfs(int u, int f){for (int i = h[u]; ~i; i = ne[i]){int j = e[i];if (j == f) continue; // 防止遍历回去dfs(j, u); // 开始继续计算nodeNum[u] += nodeNum[j]; // nodeNum 初始化就为1,不用再单独+1了distSum[u] += distSum[j] + nodeNum[j]; // 等于子树距离和 + 此边要走的此数(也就是子树结点数)}}// 先序遍历void dfs2(int u, int f, int n){for (int i = h[u]; ~i; i = ne[i]){int j = e[i];if (j == f) continue;distSum[j] = distSum[u] - nodeNum[j] + (n - nodeNum[j]); // 这里用到总的节点个数了,参数加上ndfs2(j, u, n);}}vector<int> sumOfDistancesInTree(int n, vector<vector<int>>& edges) {// 初始化memset(h, -1, sizeof h);memset(distSum, 0, sizeof distSum);for (int i = 0; i < n; i++) nodeNum[i] = 1;// 构建邻接表边for (int i = 0; i < edges.size(); i++){add(edges[i][0], edges[i][1]);add(edges[i][1], edges[i][0]);}dfs(0, -1);dfs2(0, -1, n);// 截取结果vector<int> res;res.assign(distSum, distSum + n);return res;}
};

原理思路:

        首先,我们要算出每个以 i 为根结点的子树的结点数量 nodeNum[i] 和 i 到子树其他结点的距离总和distSum[i]。

        结点数量很好计算,但是 distSum[i] 如何计算呢?用例 1 举例,当计算2的distSum时:

可以发现,其不单单是子树的 dist 相加,还要加上其各自的结点数量,因为其子树的各个结点想要到达根节点都需要经过一次此边。

nodeNum[u] += nodeNum[j]; // nodeNum 初始化就为1,不用再单独+1了
distSum[u] += distSum[j] + nodeNum[j]; // 等于子树距离和 + 此边要走的此数(也就是子树结点数)

        我们会发现现在 distSum 的含义是表示根结点 i 到其子树结点的距离和,并不是我们的结果。

        那么结果(也就是节点 i 到树中每一个结点的距离总和)如何计算呢?还是拿例 1 举例,根据现在 distSum 的含义 distSum[0](也就是根节点)就是我们的一个结果,我们可以利用此结果自顶向下的遍历,找出子树结果和根结果的关系,推算出每个节点的最终distSum(真正的结果)。

        这样就有此题最关键的核心问题?如何根据根结点的结果计算出子树根结点的结果呢?

        就例 1 来说,我们还是算节结 2 的时候(这时候是第二次遍历,自顶向下),我们用已经算出结果的distSum[0] - nodeNum[2],结点 0 到各个结点的距离总和 减去 以结点2为根节点的子树结点个数,这样减去得到的数字含义为:结点 0 到 结点1 的距离(普遍来说是到其他子树的结点距离总和) 加上 结点 2 到以结点 2 为根的子树的结点距离总和。可见还不是我们要的结果,我们再把数字加上除结点2这颗子树的节点个数(此例中就为2个,也就是结点 0 和 1),为什么要加呢?还是一样的道理,结点 0 和 1 想要到达结点 2 都需要走结点0 - 2这条边两次。

distSum[j] = distSum[u] - nodeNum[j] + (n - nodeNum[j]); // 这里用到总的节点个数了,参数加上n

        这样我们就能算出结果了。至于邻接表如何建立和如何遍历是属于基础,每个人写法可能不太一样(当然原理都是一样的),这里就不再详细解释了,不会的可以去查一查。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《C++程序设计原理与实践》笔记 第20章 容器和迭代器

本章和下一章将介绍STL&#xff0c;即C标准库的容器和算法部分。关键概念序列和迭代器用于将容器&#xff08;数据&#xff09;和算法&#xff08;处理&#xff09;联系在一起。 20.1 存储和处理数据 首先考虑一个简单的例子&#xff1a;Jack和Jill各自在测量车速&#xff0c…

GO语言slice

slice: data lencap 以及存取的元素是可以安全读写的 Slice 扩容。 1&#xff0c;预估&#xff1a; 2&#xff0c;预估容量后*字节数 所需的内存 3&#xff0c;各种语言从OS上提前申请内存&#xff0c;匹配GO规则的内存

Windows搭建SVN环境

VisualSVN Server下载 https://www.visualsvn.com/products VisualSVN Server安装创建仓库创建项目创建用户创建组项目分配组VisualSVN下载 https://www.visualsvn.com/products VisualSVN安装项目检出项目检出路径&#xff1a;https://changwq:8443/svn/dev/InterfaceManage 项…

如何实时记录工序流转状态——手机扫码让进度一目了然

对于生产企业来说记录工序的进展状态非常重要&#xff0c;有一部分中小型企业会使用纸制的“工序流转卡”&#xff0c;每日收集齐后再交由专员人工录入到电脑上&#xff0c;这种方式不仅费时费力&#xff0c;还容易出错&#xff0c;更重要的是无法让管理者实时掌握各个订单的进…

【FPGA】基于C5的第一个SoC工程

文章目录 前言SoC的Linux系统搭建 前言 本文是在毕业实习期间学习FPGA的SoC开发板运行全连接神经网络实例手写体的总结。 声明&#xff1a;本文仅作记录和操作指南&#xff0c;涉及到的操作会尽量细致&#xff0c;但是由于文件过大不会分享文件&#xff0c;具体软件可以自行搜…

程序环境和预处理超详细讲解

目录 程序的翻译环境和执行环境 详解编译链接 翻译环境 编译本身也分为几个阶段 运行环境 预处理&#xff08;预编译&#xff09;详解 预定义符号 #define #define 定义标识符 #define 定义宏 #define 替换规则 #和## ## 的作用 带副作用的宏参数 宏和函数对比 …

服务器反向代理

反向代理作用 隐藏服务器信息 -> 保证内网的安全&#xff0c;通常将反向代理作为公网访问地址&#xff0c;web服务器是内网&#xff0c;即通过nginx配置外网访问web服务器内网 举例 百度的网址是&#xff1a;http://www.baidu.com &#xff0c; 现在我通过自己的服务器地…

mysql 备份

mysql 备份 1. 备份的类型2.备份的类容3. 备份工具1&#xff1a;MySQL自带的备份工具2&#xff1a;文件系统备份工具3&#xff1a;其他工具 4:备份的策略1. 直接拷贝数据库文件2. mysqldump备份数据库3. mydumper备份数据库4.lvm快照从物理角度实现几乎热备的完全备份&#xff…

Webpack原理与实战 --- Webpack 核心特性

如何使用 Webpack 实现模块化打包&#xff1f; 对模块化打包方案或工具的设想或者说是诉求&#xff1a; 能够将散落的模块打包到一起&#xff1b;能够编译代码中的新特性&#xff1b;能够支持不同种类的前端资源模块。 其中最为主流的就是 Webpack、Parcel 和 Rollup 以 We…

2023年7月广州/东莞/深圳传统行业产品经理NPDP认证招生

产品经理国际资格认证NPDP是新产品开发方面的认证&#xff0c;集理论、方法与实践为一体的全方位的知识体系&#xff0c;为公司组织层级进行规划、决策、执行提供良好的方法体系支撑。 【认证机构】 产品开发与管理协会&#xff08;PDMA&#xff09;成立于1979年&#xff0c;是…

【C++】STL——vector的有关空间的函数介绍和使用、size和capacity函数、resize和reserve函数

文章目录 1.vector的使用2.vector空间增长问题&#xff08;1&#xff09;size 获取数据个数&#xff08;2&#xff09;capacity 获取容量大小&#xff08;3&#xff09;empty 判断是否为空&#xff08;4&#xff09;resize 改变vector的size&#xff08;5&#xff09;reserve 改…

9.Ceph部署

文章目录 Ceph部署前期环境准备实验部署软件安装部署Ceph集群部署mon节点部署OSD存储节点部署mgr节点开启监控模块管理pool Ceph部署 前期环境准备 主机名public网络cluster网络角色admin192.168.242.69admin(管理节点)node01192.168.242.66192.168.242.100.11mon、mgr、osdn…