Skip to content

Commit f867249

Browse files
committed
feat: update solutions to lc problem: No.1697
No.1697.Checking Existence of Edge Length Limited Paths
1 parent 0d38234 commit f867249

File tree

7 files changed

+250
-250
lines changed

7 files changed

+250
-250
lines changed

solution/1600-1699/1697.Checking Existence of Edge Length Limited Paths/README.md

Lines changed: 144 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -52,70 +52,123 @@
5252

5353
<!-- 这里可写通用的实现逻辑 -->
5454

55-
这是一道**离线思维**的题目。
55+
**方法一:离线查询 + 并查集**
5656

57-
**离线**的意思是,一道题目会给出若干 query,而这些 query 会全部提前给出。也就是说,我们可以不必按照 query 的顺序依次对它们进行处理,而是可以按照另外某种顺序进行处理。与**离线**相对应的是**在线**,即所有 query 会依次给出,在返回第 k 个 query 的答案之前,不会获得第 k+1 个 query
57+
根据题目要求,我们需要对每个查询 $queries[i]$ 进行判断,即判断当前查询的两个点 $a$ 和 $b$ 之间是否存在一条边权小于等于 $limit$ 的路径
5858

59-
对于本题,可以转换为:将小于 limit 的所有边加入图中,判断此时 pj, qj 是否连通。可以用并查集来实现
59+
判断两点是否连通可以通过并查集来实现。另外,由于查询的顺序对结果没有影响,因此我们可以先将所有查询按照 $limit$ 从小到大排序,所有边也按照边权从小到大排序
6060

61-
以下是并查集的几个常用模板
61+
然后对于每个查询,我们从边权最小的边开始,将边权严格小于 $limit$ 的所有边加入并查集,接着利用并查集的查询操作判断两点是否连通即可
6262

63-
模板 1——朴素并查集:
63+
时间复杂度 $O(m \times \log m + q \times \log q)$,其中 $m$ 和 $q$ 分别为边数和查询数。
6464

65-
```python
66-
# 初始化,p存储每个点的父节点
67-
p = list(range(n))
65+
附并查集相关介绍以及常用模板:
6866

69-
# 返回x的祖宗节点
70-
def find(x):
71-
if p[x] != x:
72-
# 路径压缩
73-
p[x] = find(p[x])
74-
return p[x]
67+
并查集是一种树形的数据结构,顾名思义,它用于处理一些不交集的**合并****查询**问题。 它支持两种操作:
7568

69+
1. 查找(Find):确定某个元素处于哪个子集,单次操作时间复杂度 $O(\alpha(n))$
70+
1. 合并(Union):将两个子集合并成一个集合,单次操作时间复杂度 $O(\alpha(n))$
7671

77-
# 合并a和b所在的两个集合
78-
p[find(a)] = find(b)
79-
```
72+
其中 $\alpha$ 为阿克曼函数的反函数,其增长极其缓慢,也就是说其单次操作的平均运行时间可以认为是一个很小的常数。
8073

81-
模板 2——维护 size 的并查集
74+
以下是并查集的常用模板,需要熟练掌握。其中
8275

83-
```python
84-
# 初始化,p存储每个点的父节点,size只有当节点是祖宗节点时才有意义,表示祖宗节点所在集合中,点的数量
76+
- `n` 表示节点数
77+
- `p` 存储每个点的父节点,初始时每个点的父节点都是自己
78+
- `size` 只有当节点是祖宗节点时才有意义,表示祖宗节点所在集合中,点的数量
79+
- `find(x)` 函数用于查找 $x$ 所在集合的祖宗节点
80+
- `union(a, b)` 函数用于合并 $a$ 和 $b$ 所在的集合
81+
82+
```python [sol1-Python3 模板]
8583
p = list(range(n))
8684
size = [1] * n
8785

88-
# 返回x的祖宗节点
8986
def find(x):
9087
if p[x] != x:
9188
# 路径压缩
9289
p[x] = find(p[x])
9390
return p[x]
9491

95-
# 合并a和b所在的两个集合
96-
if find(a) != find(b):
97-
size[find(b)] += size[find(a)]
98-
p[find(a)] = find(b)
92+
93+
def union(a, b):
94+
pa, pb = find(a), find(b)
95+
if pa == pb:
96+
return
97+
p[pa] = pb
98+
size[pb] += size[pa]
9999
```
100100

101-
模板 3——维护到祖宗节点距离的并查集:
101+
```java [sol1-Java 模板]
102+
int[] p = new int[n];
103+
int[] size = new int[n];
104+
for (int i = 0; i < n; ++i) {
105+
p[i] = i;
106+
size[i] = 1;
107+
}
102108

103-
```python
104-
# 初始化,p存储每个点的父节点,d[x]存储x到p[x]的距离
105-
p = list(range(n))
106-
d = [0] * n
109+
int find(int x) {
110+
if (p[x] != x) {
111+
// 路径压缩
112+
p[x] = find(p[x]);
113+
}
114+
return p[x];
115+
}
107116

108-
# 返回x的祖宗节点
109-
def find(x):
110-
if p[x] != x:
111-
t = find(p[x])
112-
d[x] += d[p[x]]
113-
p[x] = t
117+
void union(int a, int b) {
118+
int pa = find(a), pb = find(b);
119+
if (pa == pb) {
120+
return;
121+
}
122+
p[pa] = pb;
123+
size[pb] += size[pa];
124+
}
125+
```
126+
127+
```cpp [sol1-C++ 模板]
128+
vector<int> p(n);
129+
iota(p.begin(), p.end(), 0);
130+
vector<int> size(n, 1);
131+
132+
int find(int x) {
133+
if (p[x] != x) {
134+
// 路径压缩
135+
p[x] = find(p[x]);
136+
}
137+
return p[x];
138+
}
139+
140+
void unite(int a, int b) {
141+
int pa = find(a), pb = find(b);
142+
if (pa == pb) return;
143+
p[pa] = pb;
144+
size[pb] += size[pa];
145+
}
146+
```
147+
148+
```go [sol1-Go 模板]
149+
p := make([]int, n)
150+
size := make([]int, n)
151+
for i := range p {
152+
p[i] = i
153+
size[i] = 1
154+
}
155+
156+
func find(x int) int {
157+
if p[x] != x {
158+
// 路径压缩
159+
p[x] = find(p[x])
160+
}
114161
return p[x]
162+
}
115163
116-
# 合并a和b所在的两个集合
117-
p[find(a)] = find(b)
118-
d[find(a)] = distance
164+
func union(a, b int) {
165+
pa, pb := find(a), find(b)
166+
if pa == pb {
167+
return
168+
}
169+
p[pa] = pb
170+
size[pb] += size[pa]
171+
}
119172
```
120173

121174
<!-- tabs:start -->
@@ -134,19 +187,14 @@ class Solution:
134187

135188
p = list(range(n))
136189
edgeList.sort(key=lambda x: x[2])
137-
138-
m = len(queries)
139-
indexes = list(range(m))
140-
indexes.sort(key=lambda i: queries[i][2])
141-
ans = [False] * m
142-
i = 0
143-
for j in indexes:
144-
pj, qj, limit = queries[j]
145-
while i < len(edgeList) and edgeList[i][2] < limit:
146-
u, v, _ = edgeList[i]
190+
j = 0
191+
ans = [False] * len(queries)
192+
for i, (a, b, limit) in sorted(enumerate(queries), key=lambda x: x[1][2]):
193+
while j < len(edgeList) and edgeList[j][2] < limit:
194+
u, v, _ = edgeList[j]
147195
p[find(u)] = find(v)
148-
i += 1
149-
ans[j] = find(pj) == find(qj)
196+
j += 1
197+
ans[i] = find(a) == find(b)
150198
return ans
151199
```
152200

@@ -163,23 +211,23 @@ class Solution {
163211
for (int i = 0; i < n; ++i) {
164212
p[i] = i;
165213
}
214+
Arrays.sort(edgeList, (a, b) -> a[2] - b[2]);
166215
int m = queries.length;
167-
Integer[] indexes = new Integer[m];
216+
boolean[] ans = new boolean[m];
217+
Integer[] qid = new Integer[m];
168218
for (int i = 0; i < m; ++i) {
169-
indexes[i] = i;
219+
qid[i] = i;
170220
}
171-
Arrays.sort(indexes, Comparator.comparingInt(i -> queries[i][2]));
172-
Arrays.sort(edgeList, Comparator.comparingInt(a -> a[2]));
173-
boolean[] ans = new boolean[m];
174-
int i = 0;
175-
for (int j : indexes) {
176-
int pj = queries[j][0], qj = queries[j][1], limit = queries[j][2];
177-
while (i < edgeList.length && edgeList[i][2] < limit) {
178-
int u = edgeList[i][0], v = edgeList[i][1];
221+
Arrays.sort(qid, (i, j) -> queries[i][2] - queries[j][2]);
222+
int j = 0;
223+
for (int i : qid) {
224+
int a = queries[i][0], b = queries[i][1], limit = queries[i][2];
225+
while (j < edgeList.length && edgeList[j][2] < limit) {
226+
int u = edgeList[j][0], v = edgeList[j][1];
179227
p[find(u)] = find(v);
180-
++i;
228+
++j;
181229
}
182-
ans[j] = find(pj) == find(qj);
230+
ans[i] = find(a) == find(b);
183231
}
184232
return ans;
185233
}
@@ -198,39 +246,31 @@ class Solution {
198246
```cpp
199247
class Solution {
200248
public:
201-
vector<int> p;
202-
203249
vector<bool> distanceLimitedPathsExist(int n, vector<vector<int>>& edgeList, vector<vector<int>>& queries) {
204-
p.resize(n);
205-
for (int i = 0; i < n; ++i) p[i] = i;
206-
sort(edgeList.begin(), edgeList.end(), [](const auto& e1, const auto& e2) {
207-
return e1[2] < e2[2];
208-
});
250+
vector<int> p(n);
251+
iota(p.begin(), p.end(), 0);
252+
sort(edgeList.begin(), edgeList.end(), [](auto& a, auto& b) { return a[2] < b[2]; });
253+
function<int(int)> find = [&](int x) -> int {
254+
if (p[x] != x) p[x] = find(p[x]);
255+
return p[x];
256+
};
209257
int m = queries.size();
210-
vector<int> indexes(m);
211-
for (int i = 0; i < m; ++i) indexes[i] = i;
212-
sort(indexes.begin(), indexes.end(), [&](int i, int j) {
213-
return queries[i][2] < queries[j][2];
214-
});
215-
216-
vector<bool> ans(m, false);
217-
int i = 0;
218-
for (int j : indexes) {
219-
int pj = queries[j][0], qj = queries[j][1], limit = queries[j][2];
220-
while (i < edgeList.size() && edgeList[i][2] < limit) {
221-
int u = edgeList[i][0], v = edgeList[i][1];
258+
vector<bool> ans(m);
259+
vector<int> qid(m);
260+
iota(qid.begin(), qid.end(), 0);
261+
sort(qid.begin(), qid.end(), [&](int i, int j) { return queries[i][2] < queries[j][2]; });
262+
int j = 0;
263+
for (int i : qid) {
264+
int a = queries[i][0], b = queries[i][1], limit = queries[i][2];
265+
while (j < edgeList.size() && edgeList[j][2] < limit) {
266+
int u = edgeList[j][0], v = edgeList[j][1];
222267
p[find(u)] = find(v);
223-
++i;
268+
++j;
224269
}
225-
ans[j] = find(pj) == find(qj);
270+
ans[i] = find(a) == find(b);
226271
}
227272
return ans;
228273
}
229-
230-
int find(int x) {
231-
if (p[x] != x) p[x] = find(p[x]);
232-
return p[x];
233-
}
234274
};
235275
```
236276
@@ -239,37 +279,33 @@ public:
239279
```go
240280
func distanceLimitedPathsExist(n int, edgeList [][]int, queries [][]int) []bool {
241281
p := make([]int, n)
242-
for i := 0; i < n; i++ {
282+
for i := range p {
243283
p[i] = i
244284
}
245-
var find func(x int) int
285+
sort.Slice(edgeList, func(i, j int) bool { return edgeList[i][2] < edgeList[j][2] })
286+
var find func(int) int
246287
find = func(x int) int {
247288
if p[x] != x {
248289
p[x] = find(p[x])
249290
}
250291
return p[x]
251292
}
252-
sort.Slice(edgeList, func(i, j int) bool {
253-
return edgeList[i][2] < edgeList[j][2]
254-
})
255293
m := len(queries)
256-
indexes := make([]int, m)
257-
for i := 0; i < m; i++ {
258-
indexes[i] = i
259-
}
260-
sort.Slice(indexes, func(i, j int) bool {
261-
return queries[indexes[i]][2] < queries[indexes[j]][2]
262-
})
294+
qid := make([]int, m)
263295
ans := make([]bool, m)
264-
i := 0
265-
for _, j := range indexes {
266-
pj, qj, limit := queries[j][0], queries[j][1], queries[j][2]
267-
for i < len(edgeList) && edgeList[i][2] < limit {
268-
u, v := edgeList[i][0], edgeList[i][1]
296+
for i := range qid {
297+
qid[i] = i
298+
}
299+
sort.Slice(qid, func(i, j int) bool { return queries[qid[i]][2] < queries[qid[j]][2] })
300+
j := 0
301+
for _, i := range qid {
302+
a, b, limit := queries[i][0], queries[i][1], queries[i][2]
303+
for j < len(edgeList) && edgeList[j][2] < limit {
304+
u, v := edgeList[j][0], edgeList[j][1]
269305
p[find(u)] = find(v)
270-
i++
306+
j++
271307
}
272-
ans[j] = find(pj) == find(qj)
308+
ans[i] = find(a) == find(b)
273309
}
274310
return ans
275311
}

0 commit comments

Comments
 (0)