当前位置: 首页 > news >正文

DeepSeek LeetCode 2876. 有向图访问计数 C语言实现

以下是 LeetCode 2876 「有向图访问计数」的 C 语言实现。
核心思路为拓扑排序 + 反向 BFS,时间复杂度 O(n),空间复杂度 O(n)。

```c
#include <stdlib.h>
#include <string.h>

/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* countVisitedNodes(int* edges, int edgesSize, int* returnSize) {
int n = edgesSize;
int* ans = (int*)calloc(n, sizeof(int));
*returnSize = n;

// 1. 统计入度
int* indeg = (int*)calloc(n, sizeof(int));
for (int i = 0; i < n; ++i) {
indeg[edges[i]]++;
}

// 2. 拓扑排序,移除所有树枝节点(入度为 0 的节点)
int* queue = (int*)malloc(n * sizeof(int));
int head = 0, tail = 0;
for (int i = 0; i < n; ++i) {
if (indeg[i] == 0) {
queue[tail++] = i;
}
}
while (head < tail) {
int u = queue[head++];
int v = edges[u];
indeg[v]--;
if (indeg[v] == 0) {
queue[tail++] = v;
}
}
free(queue);

// 3. 处理所有环,计算环上节点的答案
// 此时 indeg[i] > 0 的节点一定在环上
for (int i = 0; i < n; ++i) {
if (indeg[i] > 0 && ans[i] == 0) {
// 收集当前环上的所有节点
int* cycle = (int*)malloc(n * sizeof(int));
int cnt = 0;
int cur = i;
while (indeg[cur] > 0) {
cycle[cnt++] = cur;
indeg[cur] = -1; // 标记已处理
cur = edges[cur];
}
int len = cnt;
for (int j = 0; j < cnt; ++j) {
ans[cycle[j]] = len;
}
free(cycle);
}
}
free(indeg);

// 4. 构建反向图(每个节点的所有前驱)
int** rg = (int**)malloc(n * sizeof(int*));
int* prevCnt = (int*)calloc(n, sizeof(int));
// 统计每个节点的前驱数量
for (int i = 0; i < n; ++i) {
prevCnt[edges[i]]++;
}
for (int i = 0; i < n; ++i) {
rg[i] = (int*)malloc(prevCnt[i] * sizeof(int));
prevCnt[i] = 0; // 复用为当前填充下标
}
for (int i = 0; i < n; ++i) {
int to = edges[i];
rg[to][prevCnt[to]++] = i;
}

// 5. BFS 从环上节点向外更新树枝节点
int* q = (int*)malloc(n * sizeof(int));
head = 0, tail = 0;
for (int i = 0; i < n; ++i) {
if (ans[i] > 0) { // 环上节点
q[tail++] = i;
}
}
while (head < tail) {
int u = q[head++];
for (int j = 0; j < prevCnt[u]; ++j) {
int v = rg[u][j];
if (ans[v] == 0) {
ans[v] = ans[u] + 1;
q[tail++] = v;
}
}
}
free(q);
for (int i = 0; i < n; ++i) free(rg[i]);
free(rg);
free(prevCnt);

return ans;
}
```

代码说明

1. 入度统计:每个节点指向 edges[i],因此目标节点的入度加一。
2. 拓扑排序:将所有入度为 0 的节点入队,删除它们(将其指向的节点入度减 1),直到队列为空。此时剩余 indeg[i] > 0 的节点都在环上。
3. 环处理:遍历所有节点,若 indeg[i] > 0 且 ans[i] == 0,则沿着 edges 收集整个环,环长即为答案。
4. 反向图构建:为每个节点记录它的所有前驱节点,用于从环向外传播答案。
5. BFS 传播:将环上节点作为起点,不断向它的前驱节点传播答案(ans[prev] = ans[cur] + 1),直到所有节点被填充。

复杂度分析

· 时间复杂度:O(n),每个节点和每条边都只被处理常数次。
· 空间复杂度:O(n),用于存储入度、队列、反向图等。

http://www.cnnetsun.cn/news/2684072.html

相关文章:

  • d3dx9_43.dll 丢失报错原因分析及三种标准修复方法
  • 用Arduino和MLX90614做个非接触测温仪,5分钟搞定硬件连接与代码调试
  • 自动化始于心智:从任务复制到思维系统的认知重构
  • 告别插件!UE5.2+ 手搓一个带鼠标悬停交互的UMG平滑曲线图控件
  • 告别烘焙!用UE5 Lumen打造动态昼夜循环,这光影效果太真实了
  • 自动语音识别技术演进:从HMM到Transformer的工程实践与落地挑战
  • 别再瞎调了!BetaFlight电流校准保姆级实操指南(附自动化计算表格)
  • 自动化时代财富分配新解:GDP挂钩UBI如何实现技术红利共享
  • 网络服务作业
  • 2026年Notepad++ 下载、安装及使用全攻略(附详细图文)
  • 三菱PLC编程避坑指南:四则运算和数据类型转换里那些新手必踩的‘雷’(附解决方案)
  • 从协议到代码:手把手拆解一个NR C-DRX Inactivity Timer的仿真模型(附Python示例)
  • Cadence SPB17.4导出的Gerber,为啥CAM350 V10.7CN死活读不了槽孔文件?一个版本兼容的‘中间人’解法
  • 学习JS第十三天
  • 构建SOC 2合规云原生数据湖:金融级数据安全架构实战
  • AI生成虚假产品图片诈骗:新型网络钓鱼与联盟营销的融合威胁
  • 机器学习实战:从数据理解到模型部署的工程化思维
  • CoinTrail-智能Ai记账软件
  • ARM VFP11浮点异常处理机制与优化实践
  • Ubuntu虚拟机开机卡在systemd服务?别慌,这可能是你的磁盘空间在求救
  • 拆解AI五大核心恐惧:从工作替代到人类价值的务实思考
  • Godot4.2编辑器插件开发入门:把你的自定义网格节点变成可拖拽的‘可视化工具’
  • 一次搞定Dell T440双系统启动丢失:从UEFI Boot报错到恢复Ubuntu/Windows引导
  • LOIC终极指南:如何安全使用开源网络压力测试工具
  • 一根网线搞定!零显示器用Windows笔记本SSH连接树莓派5的保姆级避坑指南
  • 告别卡顿!用NoMachine远程流畅运行Linux桌面Firefox的保姆级配置指南
  • 本地服务注册测试环境Nacos失败?别慌,排查这个9848端口映射问题就对了
  • CPU也能跑!用fast-whisper在本地电脑搞定中文语音转文字(附tiny模型下载与转换教程)
  • 传奇 3 手游 6 月最新下载官网:正版 1.45 复刻三端互通安全下载指南
  • 告别Unity后,用Unreal Engine 5做3D独立游戏是‘杀鸡用牛刀’吗?聊聊我的实际体验与配置优化