ARST打卡第233周[233/521]

Algorithm

lc2316_统计无向图中无法互相到达点对数

思路:
其实就是计算连通图的个数,然后每个连通图之间的点数,然后再相互之间计算点对数

直接用 hash 表来表示一个连通图里面的点的个数。—不行,得用并查集。
并查集又忘了怎么写了,得看看板子,但整体是这个思路,看看题解吧。

看题解发现并查集版本其实一开始并不知道连通图的个数。要知道连通图的个数需要dfs版本的。

草稿

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 并查集忘了怎么写的草稿版
class Solution {
public:
int fa(int n) {
if
}

long long countPairs(int n, vector<vector<int>>& edges) {
long long ans;
if (0 == edges.size()) {
ans = (long long)n * (n-1) / 2;
return ans;
}
vector<unordered_set<int>> maps;
unordered_set<int> tmp_map;
if
}
};

并查集法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
class UnionFind {
private:
vector<int> parents;
vector<int> sizes;
public:
UnionFind(int n) : parents(n), sizes(n, 1) {
// 类似go中的iota初始化
iota(parents.begin(), parents.end(), 0);
}
int Find(int x) {
if (parents[x] == x) {
return x;
}
return parents[x] = Find(parents[x]);
}
void Union(int x, int y) {
int rx = Find(x), ry = Find(y);
if (rx != ry) {
if (sizes[rx] > sizes[ry]) {
// 能让size小的y中极端点走更短的size[ry]路径就能找到根
parents[ry] = rx;
sizes[rx] += sizes[ry];
} else {
parents[rx] = ry;
sizes[ry] += sizes[rx];
}
}
}
int GetSize(int x) {
return sizes[x];
}
};

class Solution {
public:
long long countPairs(int n, vector<vector<int>> &edges) {
UnionFind uf(n);
for (const auto &edge : edges) {
uf.Union(edge[0], edge[1]);
}
long long res = 0;
for (int i = 0; i < n; i++) {
// 当前点的联通图外的所有的点的个数。
res += n - uf.GetSize(uf.Find(i));
}
return res / 2;
}
};

// 链接:https://leetcode.cn/problems/count-unreachable-pairs-of-nodes-in-an-undirected-graph/

dfs版

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution:
def countPairs(self, n: int, edges: List[List[int]]) -> int:
graph = [[] for _ in range(n)]
for x, y in edges:
graph[x].append(y)
graph[y].append(x)

visited = [False] * n
# 可以计算一个连通图的点数
def dfs(x: int) -> int:
visited[x] = True
count = 1
for y in graph[x]:
if not visited[y]:
count += dfs(y)
return count

res = 0
for i in range(n):
if not visited[i]:
count = dfs(i)
res += count * (n - count)
return res // 2

# 链接:https://leetcode.cn/problems/count-unreachable-pairs-of-nodes-in-an-undirected-graph/

Review

How to Pronounce Contractions: American English Pronunciation

Pronounce Contractions is import to get someone’s meaning in communication.

Tips

扩充语料库的训练方法实战

Share-rocksdb中Env线程池实现中,线程数不够时,为啥要唤醒所有的线程

在RocksDB中,Env线程池用于执行各种后台任务,如磁盘文件的读写、数据压缩等。这个线程池中有多个线程,每个线程负责处理任务队列中的任务。

假设有一个任务队列,里面有很多任务需要执行,但同时线程池中的线程数不够,也就是说有更多的任务要执行,但可用的线程有限。在这种情况下,当一个任务需要执行时,RocksDB的代码可能会唤醒一个线程来处理这个任务。

问题是,唤醒哪个线程来执行任务?如果只唤醒一个线程,但不知道这个线程的当前状态,有可能这个线程已经在执行终止操作,也就是即将结束它的生命周期。如果唤醒了一个即将结束的线程,任务可能无法被及时处理。

为了解决这个问题,RocksDB选择唤醒所有的线程。这样,无论哪个线程被唤醒,都有机会去执行任务,而不会因为唤醒了即将终止的线程而导致任务被延迟或无法执行。

唤醒所有线程可以确保任务尽快得到处理,而不受线程终止状态的干扰。这是一种策略,以确保任务的顺利执行和并发性。

注意:

  • 唤醒线程的操作并不直接控制线程的终止状态。唤醒操作的目的是通知线程池中的线程有任务可以执行,但不会影响线程的生命周期。线程的终止状态通常由线程池的管理机制来控制。
  • 唤醒所有线程的操作并不会使正在执行任务的线程抛弃当前任务来选择新任务。当所有线程都被唤醒后,它们会根据线程池的任务调度策略来决定下一步执行哪个任务。—一般情况下是有任务的线程继续做当前任务,然后空闲线程做新任务,而要终止的线程去终止。