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

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

作者推荐

【动态规划】【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;

};


相关文章
|
4天前
|
存储 负载均衡 算法
基于 C++ 语言的迪杰斯特拉算法在局域网计算机管理中的应用剖析
在局域网计算机管理中,迪杰斯特拉算法用于优化网络路径、分配资源和定位故障节点,确保高效稳定的网络环境。该算法通过计算最短路径,提升数据传输速率与稳定性,实现负载均衡并快速排除故障。C++代码示例展示了其在网络模拟中的应用,为企业信息化建设提供有力支持。
35 15
|
4天前
|
存储 算法 数据处理
公司局域网管理中的哈希表查找优化 C++ 算法探究
在数字化办公环境中,公司局域网管理至关重要。哈希表作为一种高效的数据结构,通过哈希函数将关键值(如IP地址、账号)映射到数组索引,实现快速的插入、删除与查找操作。例如,在员工登录验证和设备信息管理中,哈希表能显著提升效率,避免传统线性查找的低效问题。本文以C++为例,展示了哈希表在局域网管理中的具体应用,包括设备MAC地址与IP分配的存储与查询,并探讨了优化哈希函数和扩容策略,确保网络管理高效准确。
|
18天前
|
运维 监控 JavaScript
内网网管软件中基于 Node.js 的深度优先搜索算法剖析
内网网管软件在企业网络中不可或缺,涵盖设备管理、流量监控和安全防护。本文基于Node.js实现深度优先搜索(DFS)算法,解析其在网络拓扑遍历中的应用。通过DFS,可高效获取内网设备连接关系,助力故障排查与网络规划。代码示例展示了图结构的构建及DFS的具体实现,为内网管理提供技术支持。
38 11
|
18天前
|
机器学习/深度学习 算法
算法系列之搜索算法-深度优先搜索DFS
深度优先搜索和广度优先搜索一样,都是对图进行搜索的算法,目的也都是从起点开始搜索,直到到达顶点。深度优先搜索会沿着一条路径不断的往下搜索,直到不能够在继续为止,然后在折返,开始搜索下一条候补路径。
94 62
算法系列之搜索算法-深度优先搜索DFS
|
1天前
|
算法 安全 Java
算法系列之深度优先搜索寻找妖怪和尚过河问题的所有方式
在算法学习中,深度优先搜索(DFS)是一种常用的图搜索算法,通过递归或栈实现,适合路径搜索、连通性、拓扑排序、回溯、生成、环路检测、强连通分量和可达性等问题。本文将介绍如何利用深度优先搜索解决“妖怪和尚过河问题”的所有方式。
52 26
算法系列之深度优先搜索寻找妖怪和尚过河问题的所有方式
|
4天前
|
算法 Java
算法系列之数据结构-Huffman树
Huffman树(哈夫曼树)又称最优二叉树,是一种带权路径长度最短的二叉树,常用于信息传输、数据压缩等方面。它的构造基于字符出现的频率,通过将频率较低的字符组合在一起,最终形成一棵树。在Huffman树中,每个叶节点代表一个字符,而每个字符的编码则是从根节点到叶节点的路径所对应的二进制序列。
28 3
 算法系列之数据结构-Huffman树
|
22天前
|
存储 监控 算法
员工屏幕监控系统之 C++ 图像差分算法
在现代企业管理中,员工屏幕监控系统至关重要。本文探讨了其中常用的图像差分算法,该算法通过比较相邻两帧图像的像素差异,检测屏幕内容变化,如应用程序切换等。文中提供了C++实现代码,并介绍了其在实时监控、异常行为检测和数据压缩等方面的应用,展示了其实现简单、效率高的特点。
44 15
|
22天前
|
算法 Serverless 数据处理
从集思录可转债数据探秘:Python与C++实现的移动平均算法应用
本文探讨了如何利用移动平均算法分析集思录提供的可转债数据,帮助投资者把握价格趋势。通过Python和C++两种编程语言实现简单移动平均(SMA),展示了数据处理的具体方法。Python代码借助`pandas`库轻松计算5日SMA,而C++代码则通过高效的数据处理展示了SMA的计算过程。集思录平台提供了详尽且及时的可转债数据,助力投资者结合算法与社区讨论,做出更明智的投资决策。掌握这些工具和技术,有助于在复杂多变的金融市场中挖掘更多价值。
47 12
|
13天前
|
存储 监控 算法
公司监控上网软件架构:基于 C++ 链表算法的数据关联机制探讨
在数字化办公时代,公司监控上网软件成为企业管理网络资源和保障信息安全的关键工具。本文深入剖析C++中的链表数据结构及其在该软件中的应用。链表通过节点存储网络访问记录,具备高效插入、删除操作及节省内存的优势,助力企业实时追踪员工上网行为,提升运营效率并降低安全风险。示例代码展示了如何用C++实现链表记录上网行为,并模拟发送至服务器。链表为公司监控上网软件提供了灵活高效的数据管理方式,但实际开发还需考虑安全性、隐私保护等多方面因素。
20 0
公司监控上网软件架构:基于 C++ 链表算法的数据关联机制探讨
|
19天前
|
存储 人工智能 算法
【深度优先搜索篇】走迷宫的魔法:算法如何破解迷宫的神秘密码
【深度优先搜索篇】走迷宫的魔法:算法如何破解迷宫的神秘密码