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

DeepSeek LeetCode 2421. 好路径的数目 public int numberOfGoodPaths(int[] vals

这道题要求统计“好路径”的数量,定义是路径起点和终点的值相等,且路径上所有节点的值都 ≤ 这个值。

我来帮你梳理思路并给出可直接使用的代码。

---

思路分析

1. 关键条件理解
· 路径的起点值 vals[u] = 终点值 vals[v]。
· 路径上所有中间节点的值 ≤ 起点值(所以其实是 ≤ vals[u])。
· 因此,对于节点值相等的两个节点,如果它们之间的路径上所有节点值都 ≤ 这个值,则这条路径就是“好路径”。
2. 并查集 + 值从小到大处理
· 将所有节点按值升序排序。
· 每次处理一种值 v 的所有节点时,只考虑值 ≤ v 的边来连接(按值升序逐步加边)。
· 在加入值 v 的节点及其与值 ≤ v 节点的边后,使用并查集将连通块合并。
· 对于当前值 v,每个连通块内具有值 v 的节点数 cnt,它们两两之间的路径都是好路径(同值且值最大,路径上无更大值节点,因为更大的值还没加进来)。
· 对每个值 v,贡献为 C(cnt, 2) + cnt(每个节点自身也算一条长度为 0 的路径)。
3. 算法步骤
· 按值排序节点索引。
· 按值升序排序所有边(或边只按两端节点的较大值排序)。
· 顺序枚举每个值,对于当前所有值 ≤ 当前值的节点,利用并查集合并它们之间的边。
· 统计每个连通块中当前值节点个数,累加贡献。
4. 时间复杂度
· 并查集 + 排序节点 + 排序边:O(n log n + m log m),其中 m = edges.length。

---

代码实现

```java
import java.util.*;

class Solution {
public int numberOfGoodPaths(int[] vals, int[][] edges) {
int n = vals.length;
// 按节点值升序存储节点索引
List<Integer> nodes = new ArrayList<>();
for (int i = 0; i < n; i++) nodes.add(i);
nodes.sort(Comparator.comparingInt(a -> vals[a]));

// 建图:邻接表
List<Integer>[] graph = new List[n];
for (int i = 0; i < n; i++) graph[i] = new ArrayList<>();
for (int[] e : edges) {
int u = e[0], v = e[1];
graph[u].add(v);
graph[v].add(u);
}

// 并查集
int[] parent = new int[n];
int[] size = new int[n];
for (int i = 0; i < n; i++) {
parent[i] = i;
size[i] = 1;
}

// 按值升序处理节点
int ans = 0;
boolean[] active = new boolean[n];
for (int i = 0; i < n; ) {
int curVal = vals[nodes.get(i)];
// 收集所有值等于 curVal 的节点
List<Integer> curNodes = new ArrayList<>();
while (i < n && vals[nodes.get(i)] == curVal) {
curNodes.add(nodes.get(i));
i++;
}

// 将所有相邻的、值 <= curVal 的节点合并(即当前 active 的节点)
for (int u : curNodes) {
for (int v : graph[u]) {
if (active[v]) {
union(parent, size, u, v);
}
}
active[u] = true;
}

// 统计当前值 curVal 在同一个连通块中的数量
Map<Integer, Integer> cnt = new HashMap<>();
for (int u : curNodes) {
int root = find(parent, u);
cnt.put(root, cnt.getOrDefault(root, 0) + 1);
}

// 组合数 C(cnt,2) + cnt
for (int c : cnt.values()) {
ans += c * (c + 1) / 2;
}
}
return ans;
}

private int find(int[] parent, int x) {
if (parent[x] != x) {
parent[x] = find(parent, parent[x]);
}
return parent[x];
}

private void union(int[] parent, int[] size, int a, int b) {
int ra = find(parent, a);
int rb = find(parent, b);
if (ra == rb) return;
if (size[ra] < size[rb]) {
parent[ra] = rb;
size[rb] += size[ra];
} else {
parent[rb] = ra;
size[ra] += size[rb];
}
}
}
```

---

简要解释

· active 数组标记当前已经允许使用的节点(值 ≤ 当前处理的值)。
· 处理值 v 时,先把这些节点标记为 active,然后通过已激活的边将它们合并到同一个连通块。
· 统计每一个连通块中当前值 v 的节点数量,它们两两之间都是好路径。
· 加上自己到自己的路径(单节点路径)。㇏

http://www.jsqmd.com/news/833591/

相关文章:

  • LrcHelper终极指南:3分钟掌握网易云音乐双语歌词下载技巧
  • Token工厂,移动,电信,联通,华为,阿里,百度,All in token ,DeepSeek V4 点火 Token 经济后,迈富时的“场景 Token 工厂”该被看见了
  • 5分钟掌握小红书无水印下载:让内容保存效率提升300%
  • 免费城通网盘解析神器:ctfileGet让你告别蜗牛下载速度![特殊字符]
  • UEFITool终极指南:轻松解析和编辑UEFI固件的开源利器
  • 如何轻松掌握猫抓视频嗅探:新手也能快速上手的完整指南
  • UEFITool完整指南:轻松查看和编辑UEFI固件映像的终极工具
  • 城通网盘高速解析终极指南:如何免费实现40倍下载提速
  • chlgref wasm算法分析
  • LinuxARP邻居表自动化巡检实践
  • 3分钟掌握Seraphine:英雄联盟智能助手完全指南
  • NCM格式转换实战指南:ncmdumpGUI全面解析
  • 郑州华润大厦黄金回收探店,写字楼私密门店,安全便捷无隐形消费 - 奢侈品回收测评
  • LoRA模型合并实战指南:使用vLLM与CopaW融合多技能大语言模型
  • 10分钟掌握Autovisor:智慧树网课自动化学习的完整解决方案
  • ComfyUI-VideoHelperSuite:AI视频工作流的高性能编解码架构与FFmpeg集成优化
  • UnderTheSea:越南语NLP工具箱实战指南与情感分析应用
  • 基于CircuitPython与BLE实现iOS无线编程开发板全攻略
  • 别再点‘忽略’了!开机弹出Visual C++ Runtime Library错误的终极排查指南(附Adobe软件关联排查)
  • MTKClient终极指南:解锁联发科芯片调试的专业解决方案
  • LinuxARP邻居表稳定性治理方法
  • Windows Cleaner终极指南:3分钟彻底解决C盘爆红问题!
  • 【Midjourney波普艺术风格实战指南】:20年AI视觉设计专家亲授7大核心参数调优公式与3类经典配色编码表
  • Vercel Workflow:从部署到应用生命周期自动化的范式升级
  • Joy-Con Toolkit技术方案:深入解析Switch手柄的完全控制体验
  • Apache SeaTunnel:统一数据集成平台的核心架构与生产实践
  • 终极免费游戏按键重映射工具:Hitboxer解决SOCD冲突的完整指南
  • 突破百度网盘限速:Python解析工具实现高速下载的完整指南
  • 3个步骤,用Office Custom UI Editor打造你的专属办公工具箱
  • 达达主义AI生成失败率骤降73%:基于2178次MJ V6日志分析的5大反常规参数组合(附可复用JSON模板)