news 2026/6/14 5:59:57

Kimi K2.6 思考 LeetCode 3244. 新增道路查询后的最短距离 II Java实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Kimi K2.6 思考 LeetCode 3244. 新增道路查询后的最短距离 II Java实现

这是 LeetCode 3244. 新增道路查询后的最短距离 II(困难版)的 Java 实现。

题目分析

本题与简单版(3243)的区别在于数据范围扩大到 `n, queries.length ≤ 10^5`,且关键约束:新增的道路不会交叉(不存在 `queries[i][0] < queries[j][0] < queries[i][1] < queries[j][1]`)。

由于道路不交叉,贪心策略成立:遇到捷径就走捷径是最优的。被跳过的城市不可能再出现在最短路径中。

核心思路:区间并查集

将问题转化为维护有效节点集合:
- 初始有 `n` 个城市,最短路径长度为 `n-1`(经过所有边)
- 每新增一条道路 `[u, v]`,相当于可以跳过 `(u, v)` 之间的所有城市
- 使用并查集维护"下一个有效节点",将区间 `[u, v-1]` 内的节点合并到 `v-1` 的代表元
- 每次合并减少一个连通块,答案就是当前连通块数量

并查集数组含义:`fa[i]` 表示从节点 `i` 出发,下一个未被覆盖的节点(带路径压缩)。

Java 代码

```java
class UnionFind {
public final int[] fa;

public UnionFind(int size) {
fa = new int[size];
// 初始化:每个节点指向自己
for (int i = 1; i < size; i++) {
fa[i] = i;
}
}

public int find(int x) {
if (fa[x] != x) {
fa[x] = find(fa[x]); // 路径压缩
}
return fa[x];
}
}

class Solution {
public int[] shortestDistanceAfterQueries(int n, int[][] queries) {
UnionFind uf = new UnionFind(n - 1);
int[] ans = new int[queries.length];
int cnt = n - 1; // 初始连通块数量 = 边数 = n-1

for (int qi = 0; qi < queries.length; qi++) {
int l = queries[qi][0]; // 起点
int r = queries[qi][1] - 1; // 终点前一条边

int fr = uf.find(r); // 找到 r 所在集合的代表元

// 遍历 [l, r) 区间内的所有节点,将它们合并到 fr
for (int i = uf.find(l); i < r; i = uf.find(i + 1)) {
uf.fa[i] = fr; // 直接指向代表元
cnt--; // 每合并一次,连通块数减1
}

ans[qi] = cnt;
}

return ans;
}
}
```

代码解释

关键部分 说明
`fa[i]` 节点 `i` 的父节点,带路径压缩
`find(x)` 查找 `x` 所在集合的代表元
`cnt = n - 1` 初始最短路径经过 `n-1` 条边
`r = queries[qi][1] - 1` 将城市编号转换为边编号(城市 `i` 到 `i+1` 的边编号为 `i`)
`for (int i = uf.find(l); i < r; i = uf.find(i + 1))` 跳跃式遍历,跳过已被合并的节点,均摊 O(1)

复杂度分析

- 时间复杂度:O((n + q) × α(n)),其中 α 是阿克曼函数的反函数,近似常数。每个节点最多被合并一次。
- 空间复杂度:O(n)

另一种思路:贪心 + TreeSet

如果不使用并查集,也可以用 `TreeSet` 维护剩余城市:

```java
class Solution {
public int[] shortestDistanceAfterQueries(int n, int[][] queries) {
TreeSet<Integer> set = new TreeSet<>();
for (int i = 0; i < n; i++) {
set.add(i);
}

int[] ans = new int[queries.length];

for (int i = 0; i < queries.length; i++) {
int l = queries[i][0];
int r = queries[i][1];

// 删除 (l, r) 开区间内的所有城市
// 这些城市被捷径覆盖,不可能出现在最短路径中
Integer cur = set.higher(l); // 第一个大于 l 的元素
while (cur != null && cur < r) {
set.remove(cur);
cur = set.higher(l); // 继续找下一个
}

ans[i] = set.size() - 1; // 剩余节点数 - 1 = 边数
}

return ans;
}
}
```

时间复杂度:O((n + q) log n),在数据范围较小时也可通过,但并查集版本更优。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/14 5:52:46

OBS源独立录制插件实战指南:专业级视频制作工作流深度解析

OBS源独立录制插件实战指南&#xff1a;专业级视频制作工作流深度解析 【免费下载链接】obs-source-record 项目地址: https://gitcode.com/gh_mirrors/ob/obs-source-record OBS源独立录制插件&#xff08;OBS Source Record Plugin&#xff09;是一个革命性的OBS Stu…

作者头像 李华
网站建设 2026/6/14 5:51:46

2026泡发笋干怎么泡才能又脆又嫩?资深内行人的实操全指南

泡发笋干怎么泡才能又脆又嫩&#xff1f;资深内行人的实操全指南 到底泡发笋干怎么泡才能又脆又嫩&#xff0c;核心秘诀就是“冷水冷藏慢泡四十八小时&#xff0c;加上大火原汤水煮四十分钟”&#xff0c;千万别想着用开水去走捷径速泡。 我们在竹笋加工和生鲜供应链行业深耕了…

作者头像 李华
网站建设 2026/6/14 5:48:32

嵌入式设备搞实时语音?实测对比SpeexDSP与WebRTC 3A的CPU占用和效果

嵌入式实时语音处理实战&#xff1a;SpeexDSP与WebRTC 3A的深度性能博弈在智能门禁对讲系统里突然听到刺耳的回声&#xff0c;或是车载语音助手在高速行驶时无法识别指令——这些典型场景揭示了嵌入式语音处理的核心矛盾&#xff1a;有限的硬件资源与复杂的声学环境之间的对抗。…

作者头像 李华