【深度优先搜索】【C++算法】834 树中距离之和

news2024/11/16 21:37:21

作者推荐

【动态规划】【map】【C++算法】1289. 下降路径最小和 II

本文涉及知识点

深度优先搜索 树 图论

LeetCode834 树中距离之和

给定一个无向、连通的树。树中有 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]
参数:
1 <= n <= 3 * 104
edges.length == n - 1
edges[i].length == 2
0 <= ai, bi < n
ai != bi
给定的输入保证为有效的树

深度优先搜索

假定节点0是树的根。
一,通过深度优先搜索计算m_vSubNodeCounts[i] ,以i为根节点的子树的节点数量。
二,通过深度优先搜索计算0到所有节点的距离。
DFSDis返回值是: cur到所有子孙节点的距离。
三,深度优先搜索,通过父节点到各点距离,计算当前节点到各点距离。
当前节点 和 当前节点的子孙节点 到 当前节点 的距离比到当前节点的父节点少1。
其它节点 到当前节点的距离比到当前节点的父节点的距离多1。

代码

核心代码

class CNeiBo2
{
public:
	CNeiBo2(int n, bool bDirect, int iBase = 0) :m_iN(n), m_bDirect(bDirect), m_iBase(iBase)
	{
		m_vNeiB.resize(n);
	}
	CNeiBo2(int n, vector<vector<int>>& edges, bool bDirect, int iBase = 0) :m_iN(n), m_bDirect(bDirect), m_iBase(iBase)
	{
		m_vNeiB.resize(n);
		for (const auto& v : edges)
		{
			m_vNeiB[v[0] - iBase].emplace_back(v[1] - iBase);
			if (!bDirect)
			{
				m_vNeiB[v[1] - iBase].emplace_back(v[0] - iBase);
			}
		}
	}
	inline void Add(int iNode1, int iNode2)
	{
		iNode1 -= m_iBase;
		iNode2 -= m_iBase;
		m_vNeiB[iNode1].emplace_back(iNode2);
		if (!m_bDirect)
		{
			m_vNeiB[iNode2].emplace_back(iNode1);
		}
	}
	const int m_iN;
	const bool m_bDirect;
	const int m_iBase;
	vector<vector<int>> m_vNeiB;
};


class Solution {
public:
	vector<int> sumOfDistancesInTree(int n, vector<vector<int>>& edges) {
		m_vSubNodeCounts.resize(n);
		m_vRet.resize(n);
		CNeiBo2 neiBo(n, edges, false);
		DFSSubNodeCount(neiBo, 0, -1);
		m_vRet[0] = DFSDis(neiBo, 0, -1);
		DFS(neiBo, 0, -1);
		return m_vRet;
	}
	void DFS(const CNeiBo2& neiBo, int cur, int parent)
	{
		if (-1 != parent)
		{
			m_vRet[cur] = m_vRet[parent] - m_vSubNodeCounts[cur] + (m_vSubNodeCounts.size() - m_vSubNodeCounts[cur]);
		}
		for (const auto& next : neiBo.m_vNeiB[cur])
		{
			if (parent == next)
			{
				continue;
			}
			DFS(neiBo, next, cur);
		}
	}
	int DFSSubNodeCount(const CNeiBo2& neiBo,int cur,int parent)
	{
		int iRet = 1;
		for (const auto& next : neiBo.m_vNeiB[cur])
		{
			if (parent == next)
			{
				continue;
			}
			iRet += DFSSubNodeCount(neiBo, next, cur);
		}
		return m_vSubNodeCounts[cur] = iRet;
	}
	int DFSDis(const CNeiBo2& neiBo, int cur, int parent)	
	{
		int iDis = m_vSubNodeCounts[cur]-1;
		for (const auto& next : neiBo.m_vNeiB[cur])
		{
			if (parent == next)
			{
				continue;
			}
			iDis += DFSDis(neiBo, next, cur);
		}
		return iDis;
	}
	vector<int> m_vSubNodeCounts,m_vRet;
};

测试用例

template<class T>
void Assert(const T& t1, const T& t2)
{
	assert(t1 == t2);
}

template<class T>
void Assert(const vector<T>& v1, const vector<T>& v2)
{
	if (v1.size() != v2.size())
	{
		assert(false);
		return;
	}
	for (int i = 0; i < v1.size(); i++)
	{
		Assert(v1[i], v2[i]);
	}

}

int main()
{
	int n;
	vector<vector<int>> edges;
	{
		Solution sln;
		n = 6, edges = { {0,1},{0,2},{2,3},{2,4},{2,5} };
		auto res = sln.sumOfDistancesInTree(n, edges);
		Assert(vector<int>{8, 12, 6, 10, 10, 10}, res);
	}
	{
		Solution sln;
		n = 1, edges = {};
		auto res = sln.sumOfDistancesInTree(n, edges);
		Assert(vector<int>{0}, res);
	}
	{
		Solution sln;
		n = 2, edges = { {1,0} };
		auto res = sln.sumOfDistancesInTree(n, edges);
		Assert(vector<int>{1,1}, res);
	}
	{
		Solution sln;
		n = 3, edges = { {2,1},{0,2} };
		auto res = sln.sumOfDistancesInTree(n, edges);
		Assert(vector<int>{3,3,2}, res);
	}
}

2023年1月

class Solution {
public:
vector sumOfDistancesInTree(int n, vector<vector>& edges) {
m_n = n;
m_vChildDis.assign(n, -1);
m_vChildNum.resize(n, -1);
m_vNP.resize(n);
m_vTotalNum.resize(n);
for (auto& e : edges)
{
m_vNP[e[0]].push_back(e[1]);
m_vNP[e[1]].push_back(e[0]);
}
dfs1(0, -1);
dfs2(0, -1);
return m_vTotalNum;
}
void dfs1(int iCur, const int iParent)
{
int iDis = 0;
int iNum = 0;
for (const auto& next : m_vNP[iCur])
{
if (iParent == next)
{
continue;
}
dfs1(next, iCur);
iDis += m_vChildDis[next];
iNum += m_vChildNum[next];
}
m_vChildDis[iCur] = iDis + iNum;
m_vChildNum[iCur] = iNum+1;
}
void dfs2(int iCur, const int iParent)
{
if (-1 == iParent)
{
m_vTotalNum[iCur] = m_vChildDis[iCur];
}
else
{
m_vTotalNum[iCur] = m_vTotalNum[iParent] - m_vChildDis[iCur] - m_vChildNum[iCur] + (m_n - m_vChildNum[iCur]) + m_vChildDis[iCur];
}
for (const auto& next : m_vNP[iCur])
{
if (iParent == next)
{
continue;
}
dfs2(next, iCur);
}
}
vector m_vChildDis;//距离子孙节点之和
vector m_vChildNum;//子孙数量之和+1
vector m_vTotalNum;
int m_n;
vector < vector > m_vNP;
};

2023年 6月

class Solution {
public:
vector sumOfDistancesInTree(int n, vector<vector>& edges) {
m_vTotalDis.resize(n);
m_vNodeNum.resize(n);
m_vLeve.resize(n);
m_vParent.assign(n, -1);
CNeiBo2 neiBo(n, edges, false);
DSFLeveAndNodeCount(neiBo.m_vNeiB, 0, -1);
m_vTotalDis[0] = std::accumulate(m_vLeve.begin(), m_vLeve.end(), 0);
//必须按父子顺序出来
DFS(neiBo.m_vNeiB, 0, -1);
return m_vTotalDis;
}
void DFS(vector<vector>& neiBo, int iCur, int iParent)
{
if (-1 != iParent)
{
m_vTotalDis[iCur] = m_vTotalDis[m_vParent[iCur]] - m_vNodeNum[iCur] + (m_vNodeNum[0] - m_vNodeNum[iCur]);
}
for (const auto& next : neiBo[iCur])
{
if (next == iParent)
{
continue;
}
DFS(neiBo, next, iCur);
}
}
void DSFLeveAndNodeCount( vector<vector>& neiBo,int iCur,int iParent)
{
if (-1 != iParent)
{
m_vLeve[iCur] = m_vLeve[iParent] + 1;
m_vParent[iCur] = iParent;
}
m_vNodeNum[iCur] = 1;
for (const auto& next : neiBo[iCur])
{
if (next == iParent)
{
continue;
}
DSFLeveAndNodeCount(neiBo,next, iCur);
m_vNodeNum[iCur] += m_vNodeNum[next];
}
}
vector m_vTotalDis,m_vNodeNum,m_vLeve,m_vParent;
};

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快

速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关

下载

想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版
https://download.csdn.net/download/he_zhidan/88348653

我想对大家说的话
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

核心类库ArrayList、hashMap等

八. 核心类库 1. ArrayList 数组缺点 ArrayList&#xff0c;它常常被用来替代数组 数组的缺点&#xff1a;不能自动扩容&#xff0c;比如已经创建了大小为 5 的数组&#xff0c;再想放入一个元素&#xff0c;就放不下了&#xff0c;需要创建更大的数组&#xff0c;还得把旧…

python 学习之 re库的基本使用(正则匹配)上

目录 一、基本用法 二、函数介绍 1、match函数 2、search 函数 3、compile 函数 4、findall 和 finditer 函数 5、sub 函数和 subn 函数 6、split 函数 一、基本用法 首先我们需要引入 re 库 代码基本框架使用两行代码实现 测试代码&#xff1a; import reret re.m…

Pandas设置图像宽高、分辨率、背景色、显示中文、增加子区域、图题、坐标名称、网格线

figure方法 figure方法可以设置绘图对象的长、宽、分辨率及背景颜色等。 import pandas as pd import matplotlib.pyplot as pltdata pd.read_csv(data/iris.csv) plt.figure(figsize(12, 3), dpi120, facecolorred) x data[sepal_length] plt.plot(x) plt.show()一个平面多…

【K8S 云原生】K8S的安全机制

目录 一、K8S安全机制概述 1、概念 2、请求apiserver资源的三个步骤&#xff1a; 一、认证&#xff1a;Anthentcation 1、认证的方式&#xff1a; 1、HTTP TOKEN&#xff1a; 2、http base&#xff1a; 3、http证书&#xff1a; 2、认证的访问类型&#xff1a; 3、签发…

【并发编程】指令集并行原理

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;并发编程 ⛺️稳重求进&#xff0c;晒太阳 指令集并行原理 名词&#xff1a; Clock Cycle Time CPU的Clock Cycle Time(时钟周期时间)&#xff0c;等于主频的倒数。意思是CPU能识别的最…

VR数字展厅,平面静态跨越到3D立体化时代

近些年&#xff0c;VR的概念被越来越多的人提起&#xff0c;较为常见的形式就是VR数字展厅。VR数字展厅的出现&#xff0c;让各地以及各行业的展厅展馆的呈现和宣传都发生了很大的改变和革新&#xff0c;同时也意味着展览传播的方式不再局限于原来的图文、视频&#xff0c;而是…

redis的备份原理

1 Redis持久化之RDB 1RDB是什么 在指定的时间间隔内将内存中的数据集快照写入磁盘&#xff0c; 也就是行话讲的Snapshot快照&#xff0c;它恢复时是将快照文件直接读到内存里 2备份是如何执行的 Redis会单独创建&#xff08;fork&#xff09;一个子进程来进行持久化&#x…

星环科技基于第五代英特尔®至强®可扩展处理器的分布式向量数据库解决方案重磅发布

12月15日&#xff0c;2023 英特尔新品发布会暨 AI 技术创新派对上&#xff0c;星环科技基于第五代英特尔至强可扩展处理器的Transwarp Hippo分布式向量数据库解决方案重磅发布。该方案利用第五代英特尔至强可扩展处理器带来的强大算力&#xff0c;实现了约 2 倍的代际性能提升&…

2021 Google Chrome RCE漏洞分析

一、复现环境&#xff1a; Win10 Google Chrome 86.0.4240.75 二、利用复现&#xff1a; 关闭沙箱安全使用命令进行关闭 &#xff0c;在正常情况下&#xff0c;浏览器沙箱提供了一个受限制的执行环境&#xff0c;以防止恶意代码对用户系统的损害。关闭沙箱可能会导致浏览器执…

银行数据仓库体系实践(7)--数据模型设计及流程

数据仓库作为全行或全公司的数据中心和总线&#xff0c;汇集了全行各系统以及外部数据&#xff0c;通过良好的系统架构可以保证系统稳定性和处理高效性&#xff0c;那如何保障系统数据的完备性、规范性和统一性呢&#xff1f;这里就需要有良好的数据分区和数据模型&#xff0c;…

「JavaSE」抽象类接口3

&#x1f387;个人主页&#xff1a;Ice_Sugar_7 &#x1f387;所属专栏&#xff1a;快来卷Java啦 &#x1f387;欢迎点赞收藏加关注哦&#xff01; 抽象类&接口3 &#x1f349;Clonable 接口和深拷贝&#x1f34c;浅拷贝和深拷贝 &#x1f349;Object类&#x1f349;抽象类…

Effective C++ 学习

Effective C浅浅学习&#xff0c;很多不太理解 尽量用const, enum, inline 替换#define尽可能使用const确认对象在使用前就已经被初始化构造&#xff0c;析构&#xff0c;赋值运算&#xff0c;拷贝构造为多态基类声明virtual析构函数不要让析构函数抛出异常不在构造和析构过程中…

javaWebssh宠物基地管理系统myeclipse开发mysql数据库MVC模式java编程计算机网页设计

一、源码特点 java ssh宠物基地管理系统是一套完善的web设计系统&#xff08;系统采用ssh框架进行设计开发&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用 B/S模式开发。开发环境为TOMCAT7.…

跨平台Recorder录音插件:支持多种格式、音频可视化、实时上传、语音识别

视频教程地址&#xff1a;【跨平台Recorder录音插件&#xff1a;支持多种格式、音频可视化、实时上传、语音识别】 https://www.bilibili.com/video/BV1jQ4y1c7e4/?share_sourcecopy_web&vd_sourcee66c0e33402a09ca7ae1f0ed3d5ecf7c /** 先引入Recorder &#xff08; 需先…

幻兽帕鲁服务器数据备份

搭建幻兽帕鲁个人服务器&#xff0c;最近不少用户碰到内存不足、游戏坏档之类的问题。做好定时备份&#xff0c;才能轻松快速恢复游戏进度 这里讲一下如何定时将服务器数据备份到腾讯云轻量对象存储服务&#xff0c;以及如何在有需要的时候进行数据恢复。服务器中间的数据迁移…

CI/CD

介绍一下CI/CD CI/CD的出现改变了开发人员和测试人员发布软件的方式,从最初的瀑布模型,到最后的敏捷开发(Agile Development),再到今天的DevOps,这是现代开发人员构建出色产品的技术路线 随着DevOps的兴起,出现了持续集成,持续交付和持续部署的新方法,传统的软件开发和交付方…

一文学习Thrift RPC

Thrift RPC引言 Thrift RPC的特点 Thrift 是一个RPC的框架&#xff0c;和Hessian RPC有什么区别&#xff0c;最重要的区别是Thrift可以做异构系统开发。 什么是异构系统&#xff0c;服务的提供者和服务的调用者是用不同语言开发的。 为什么会当前系统会有异构系统的调用&…

Vue3 Teleport 将组件传送到外层DOM位置

✨ 专栏介绍 在当今Web开发领域中&#xff0c;构建交互性强、可复用且易于维护的用户界面是至关重要的。而Vue.js作为一款现代化且流行的JavaScript框架&#xff0c;正是为了满足这些需求而诞生。它采用了MVVM架构模式&#xff0c;并通过数据驱动和组件化的方式&#xff0c;使…

音频前置放大器电路图大全

音频前置放大器电路图&#xff08;一&#xff09; 在本设计中&#xff0c;前置放大器的增益控制采用直流音量控制方式&#xff0c;其具体实现如图1所示。前置放大器是由全差分运放和电阻构成的反相比例放大器&#xff0c;其增益由反馈电阻与输人电阻的比值决定。外部输人的直流…

【Leetcode】2859. 计算 K 置位下标对应元素的和

文章目录 题目思路代码结果 题目 题目链接 给你一个下标从 0 开始的整数数组 nums 和一个整数 k 。 请你用整数形式返回 nums 中的特定元素之和 &#xff0c;这些特定元素满足&#xff1a;其对应下标的二进制表示中恰存在 k 个置位。 整数的二进制表示中的 1 就是这个整数的…