【深度优先搜索】【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;

};


相关文章
|
10月前
|
存储 监控 算法
基于 C++ 哈希表算法实现局域网监控电脑屏幕的数据加速机制研究
企业网络安全与办公管理需求日益复杂的学术语境下,局域网监控电脑屏幕作为保障信息安全、规范员工操作的重要手段,已然成为网络安全领域的关键研究对象。其作用类似网络空间中的 “电子眼”,实时捕获每台电脑屏幕上的操作动态。然而,面对海量监控数据,实现高效数据存储与快速检索,已成为提升监控系统性能的核心挑战。本文聚焦于 C++ 语言中的哈希表算法,深入探究其如何成为局域网监控电脑屏幕数据处理的 “加速引擎”,并通过详尽的代码示例,展现其强大功能与应用价值。
212 2
|
5月前
|
存储 机器学习/深度学习 监控
网络管理监控软件的 C# 区间树性能阈值查询算法
针对网络管理监控软件的高效区间查询需求,本文提出基于区间树的优化方案。传统线性遍历效率低,10万条数据查询超800ms,难以满足实时性要求。区间树以平衡二叉搜索树结构,结合节点最大值剪枝策略,将查询复杂度从O(N)降至O(logN+K),显著提升性能。通过C#实现,支持按指标类型分组建树、增量插入与多维度联合查询,在10万记录下查询耗时仅约2.8ms,内存占用降低35%。测试表明,该方案有效解决高负载场景下的响应延迟问题,助力管理员快速定位异常设备,提升运维效率与系统稳定性。
286 4
|
6月前
|
机器学习/深度学习 算法 机器人
【机器人路径规划】基于深度优先搜索(Depth-First-Search,DFS)算法的机器人路径规划(Python代码实现)
【机器人路径规划】基于深度优先搜索(Depth-First-Search,DFS)算法的机器人路径规划(Python代码实现)
342 3
|
10月前
|
存储 机器学习/深度学习 算法
KMP、Trie树 、AC自动机‌ ,三大算法实现 优雅 过滤 netty 敏感词
KMP、Trie树 、AC自动机‌ ,三大算法实现 优雅 过滤 netty 敏感词
KMP、Trie树 、AC自动机‌ ,三大算法实现 优雅 过滤 netty  敏感词
|
8月前
|
监控 算法 安全
基于 C# 基数树算法的网络屏幕监控敏感词检测技术研究
随着数字化办公和网络交互迅猛发展,网络屏幕监控成为信息安全的关键。基数树(Trie Tree)凭借高效的字符串处理能力,在敏感词检测中表现出色。结合C#语言,可构建高时效、高准确率的敏感词识别模块,提升网络安全防护能力。
210 2
|
10月前
|
监控 算法 数据处理
基于 C++ 的 KD 树算法在监控局域网屏幕中的理论剖析与工程实践研究
本文探讨了KD树在局域网屏幕监控中的应用,通过C++实现其构建与查询功能,显著提升多维数据处理效率。KD树作为一种二叉空间划分结构,适用于屏幕图像特征匹配、异常画面检测及数据压缩传输优化等场景。相比传统方法,基于KD树的方案检索效率提升2-3个数量级,但高维数据退化和动态更新等问题仍需进一步研究。未来可通过融合其他数据结构、引入深度学习及开发增量式更新算法等方式优化性能。
252 17
|
9月前
|
存储 机器学习/深度学习 算法
基于 C++ 的局域网访问控制列表(ACL)实现及局域网限制上网软件算法研究
本文探讨局域网限制上网软件中访问控制列表(ACL)的应用,分析其通过规则匹配管理网络资源访问的核心机制。基于C++实现ACL算法原型,展示其灵活性与安全性。文中强调ACL在企业与教育场景下的重要作用,并提出性能优化及结合机器学习等未来研究方向。
241 4
|
8月前
|
存储 监控 算法
基于跳表数据结构的企业局域网监控异常连接实时检测 C++ 算法研究
跳表(Skip List)是一种基于概率的数据结构,适用于企业局域网监控中海量连接记录的高效处理。其通过多层索引机制实现快速查找、插入和删除操作,时间复杂度为 $O(\log n)$,优于链表和平衡树。跳表在异常连接识别、黑名单管理和历史记录溯源等场景中表现出色,具备实现简单、支持范围查询等优势,是企业网络监控中动态数据管理的理想选择。
221 0
|
10月前
|
存储 监控 算法
局域网上网记录监控的 C# 基数树算法高效检索方案研究
在企业网络管理与信息安全领域,局域网上网记录监控是维护网络安全、规范网络行为的关键举措。随着企业网络数据量呈指数级增长,如何高效存储和检索上网记录数据成为亟待解决的核心问题。基数树(Trie 树)作为一种独特的数据结构,凭借其在字符串处理方面的卓越性能,为局域网上网记录监控提供了创新的解决方案。本文将深入剖析基数树算法的原理,并通过 C# 语言实现的代码示例,阐述其在局域网上网记录监控场景中的具体应用。
217 7
|
9月前
|
机器学习/深度学习 算法 搜索推荐
决策树算法如何读懂你的购物心理?一文看懂背后的科学
"你为什么总能收到刚好符合需求的商品推荐?你有没有好奇过,为什么刚浏览过的商品就出现了折扣通知?
262 0

热门文章

最新文章