「这是我参与2022首次更文挑战的第19天,活动详情查看:2022首次更文挑战」
看一百遍美女,美女也不一定是你的。但你刷一百遍算法,知识就是你的了~~
谁能九层台,不用累土起!
题目
在本问题中,有根树指满足以下条件的 有向 图。该树只有一个根节点,所有其他节点都是该根节点的后继。该树除了根节点之外的每一个节点都有且只有一个父节点,而根节点没有父节点。
输入一个有向图,该图由一个有着 n 个节点(节点值不重复,从 1 到 n)的树及一条附加的有向边构成。附加的边包含在 1 到 n 中的两个不同顶点间,这条附加的边不属于树中已存在的边。
结果图是一个以边组成的二维数组 edges 。 每个元素是一对 [ui, vi],用以表示 有向 图中连接顶点 ui 和顶点 vi 的边,其中 ui 是 vi 的一个父节点。
返回一条能删除的边,使得剩下的图是有 n 个节点的有根树。若有多个答案,返回最后出现在给定二维数组的答案。
示例 1:
输入: edges = [[1,2],[1,3],[2,3]]
输出: [2,3]
示例 2:
输入: edges = [[1,2],[2,3],[3,4],[4,1],[1,5]]
输出: [4,1]
提示:
n == edges.length3 <= n <= 1000edges[i].length == 21 <= ui, vi <= n
解题思路
- 这题我们使用并查集
- 我们先查询是否存在某个点入度为2
- 如果不存在这个点,那么我们只需要当 684_冗余连接 来做就行了,只需要返回冗余边
- 如果存在这个点,我们倒序遍历
edges - 找出能删除后组成不了环的边,将其返回
解题代码
var findRedundantDirectedConnection = function(edges) {
const n = edges.length
let union = new Union(n)
let inputPoint=new Array(n+1).fill(0)
let hasTwoPoint = -1
for(let i=0;i<n;i++){
let b = edges[i][1]
inputPoint[b]++
if(inputPoint[b]==2) {
hasTwoPoint = b
break
}
}
if(hasTwoPoint==-1){ // 不存在重复连接的节点
for(let [a,b] of edges){
if(!union.merge(a,b)) {
return [a,b]
}
}
}
for(let i = n-1;i>=0;i--){
if(edges[i][1]==hasTwoPoint){
const uf = new Union(n);
if(uf.isCircle(edges,edges[i])==null){ // 没有环,说明删除的是对的
return edges[i]
}
}
}
return
};
class Union {
constructor(n){
this.arr = new Array(n).fill(0).map((v,i)=>i) // 初始化
}
find(i){ // 查找根节点
if(this.arr[i]==i) return i
return this.find(this.arr[i])
}
connect(a,b){ // 判断是否连接
return this.find(a) == this.find(b)
}
merge(a,b){ // 合并
if(this.connect(a,b)) return false
this.arr[this.find(a)] = this.find(b)
return true
}
isCircle(edges,circle){ // 用于判断是否有环
for(let i=0;i<edges.length;i++){
if (edges[i]==circle) { // 剔除要删除的边
continue
}
if (!this.merge(edges[i][0],edges[i][1])) {
return edges[i]
}
}
return null;
}
}
如有任何问题或建议,欢迎留言讨论!