以前面试有卡学历,卡能力,甚至卡性别的都有,现在又出现一个卡形象的。最近一网友说面试一个实习生,头发乱糟糟的,像鸡窝一样,面试印象大大折扣,感觉没有得到应有的尊重,结果直接把他挂了。
我觉得应该还是能力不行,头发乱对工作没啥影响,只要不是口臭就行了。我之前遇到一个同事,那口气一说话估计能把你熏倒,每次都害怕和他沟通问题,只要和他一说话我都尽量离的稍微远一点,真的很让人头疼。不知道大家在工作用有没有遇到那种让你很刺挠的同事。
![]()
![]()
![]()
--------------下面是今天的算法题--------------
来看下今天的算法题,这题是LeetCode的第1579题:保证图可完全遍历,难度是困难。
Alice 和 Bob 共有一个无向图,其中包含 n 个节点和 3 种类型的边:
类型 1:只能由 Alice 遍历。
类型 2:只能由 Bob 遍历。
类型 3:Alice 和 Bob 都可以遍历。
给你一个数组 edges ,其中 edges[i] = [typei, ui, vi] 表示节点 ui 和 vi 之间存在类型为 typei 的双向边。请你在保证图仍能够被 Alice和 Bob 完全遍历的前提下,找出可以删除的最大边数。如果从任何节点开始,Alice 和 Bob 都可以到达所有其他节点,则认为图是可以完全遍历的。
返回可以删除的最大边数,如果 Alice 和 Bob 无法完全遍历图,则返回 -1 。
示例1:
![]()
输入:n = 4, edges = [[3,1,2],[3,2,3],[1,1,3],[1,2,4],[1,1,2],[2,3,4]] 输出:2 解释:如果删除 [1,1,2] 和 [1,1,3] 这两条边,Alice 和 Bob 仍然可以完全遍历这个图。再删除任何其他的边都无法保证图可以完全遍历。所以可以删除的最大边数是 2 。
示例2:
![]()
输入:n = 4, edges = [[3,1,2],[3,2,3],[1,1,4],[2,1,4]] 输出:0 解释:注意,删除任何一条边都会使 Alice 和 Bob 无法完全遍历这个图。
1 <= n <= 10^5
1 <= edges.length <= min(10^5, 3 * n * (n-1) / 2)
edges[i].length == 3
1 <= edges[i][0] <= 3
1 <= edges[i][1] < edges[i][2] <= n
所有元组 (typei, ui, vi) 互不相同
问题分析
这题说的是删除最多的边之后,让A(Alice)和B(Bob )都可以遍历所有的点,问删除最多的边的数量是多少?
我们假设删除最多的边之后只有A可以遍历所有的点,那么剩余边的数量就是n-1,其中n是顶点的个数,实际上就是图的一棵生成树,但不一定是最小的,我们在中讲过最小生成树。
生成树中是不能有环的,这里我们使用并查集来判断,如果两个点在同一个连通分量就不能再添加,否则会构成环,关于并查集的知识我们之前也多次介绍过,这里不在重复介绍。
如果图中既有A也有B,我们一样也可以使用并查集,这里我们使用两个并查集,一个记录A的一个记录B的。因为类型3,A和B都可以遍历,所以我们优先遍历类型3,然后再分别遍历类型1和类型2。
这题难度是困难,搞懂原理之后实际上没那么难,但代码量比较多,我们看下代码。
JAVA:
public int maxNumEdgesToRemove(int n, int[][] edges) {
// 顶点是从1开始的,不是从0开始的,这里我们把它加1.
UnionFind ufa = new UnionFind(n + 1);
UnionFind ufb = new UnionFind(n + 1);
int ans = 0;// 删除边的数量
for (int[] edge : edges) {// 公共边
if (edge[0] == 3) {
if (ufa.union(edge[1], edge[2])) {
ufb.union(edge[1], edge[2]);
} else {
ans++;// 删除该边
}
}
}
for (int[] edge : edges) { // 独占边
if (edge[0] == 1) {// Alice 独占边
if (!ufa.union(edge[1], edge[2]))
++ans;
} elseif (edge[0] == 2) { // Bob 独占边
if (!ufb.union(edge[1], edge[2]))
++ans;
}
}
// 如果连通分量不是 1 ,说明不能完全联通,返回-1。
if (ufa.cnt != 1 || ufb.cnt != 1)
return -1;
return ans;
}
// 并查集模板
privateclass UnionFind {
int[] parent;
int cnt;// 连通分量的个数
public UnionFind(int n) {
cnt = n - 1;// 初始化的时候n是加1的,这里要减去。
parent = newint[n];
for (int i = 0; i < n; ++i)
parent[i] = i;
}
private int find(int x) {
if (x != parent[x])
parent[x] = find(parent[x]);
return parent[x];
}
private boolean union(int x, int y) {
if (isConnected(x, y))
returnfalse;
int xParent = find(x);
int yParent = find(y);
parent[xParent] = yParent;
cnt--;
returntrue;
}private boolean isConnected(int x, int y) {
return find(x) == find(y);
}
}
笔者简介
博哥,真名:王一博,毕业十多年, 作者,专注于 数据结构和算法 的讲解,在全球30多个算法网站中累计做题2000多道,在公众号中写算法题解900多题,对算法题有自己独特的解题思路和解题技巧。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.