持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第21天,点击查看活动详情
今天,我们继续搞算法。
题目描述
树可以看成是一个连通且 无环 的 无向 图。
给定往一棵 n 个节点 (节点值 1~n) 的树中添加一条边后的图。添加的边的两个顶点包含在 1 到 n 中间,且这条附加的边不属于树中已存在的边。图的信息记录于长度为 n 的二维数组 edges ,edges[i] = [ai, bi] 表示图中在 ai 和 bi 之间存在一条边。
请找出一条可以删去的边,删除后可使得剩余部分是一个有着 n 个节点的树。如果有多个答案,则返回数组 edges 中最后出现的边。
题目分析
这个题目是找出一条可以删去的边,使得剩余部分是一个树。
树可以看成是一个连通且 无环 的 无向 图。这句话很重要,后续有讲解。
那怎么来找呢?我们先使用出边数组构建出一个图,一条边一条边的构建,然后遍历这个图,如果成环,就返回这条边。
我们来分析一下这个题,去掉一条成环的边,它给了这个成环的图,如下:
- edges = [[1,2], [1,3], [2,3]] 这是一个三条边的数组,如图所示成环,我们要删除一条边,使其成为一棵树,
- 那我们怎么来做呢?可以先把这个图描述出来,一条一条的画,然后进行深度优先遍历,如果成环,说明该边就是需
- 删除的边。
- 一开始,加一条:1to2,2to1, 走1,标记,然后走2标记,2走1,1标记过结束,不成环。
- 要注意2到1和1到2我们需要进行判重
- 如果一个点走过了,一圈之后,还能走,而且也判重过,说明成环,就把那条边返回即可。 我们来实现一下
解题思路
- 确定操作对象:本题中,操作对象1个edges
- 确定操作条件:如果该点没走过,就走该点,如果要已经到达的点还有曾经到过的点就跳过。
- 确定操作过程:操作过程就是深度优先遍历所有点。
- 确定结果返回:成环则返回最终结果。
代码
class Solution {
public:
vector<int> findRedundantConnection(vector<vector<int>>& edges) {
//构造一个图
int n =0;
for(vector<int>& edge : edges){
int a = edge[0];
int b = edge[1];
n = max(n,max(a,b));
}
to = vector<vector<int>>(n+1 ,vector<int>());
visited = vector<bool>(to.size(),false);
for(vector<int>& edge : edges){
int a = edge[0];
int b = edge[1];
to[a].push_back(b);
to[b].push_back(a);
hascycle =false;
for(int i = 1 ; i<=visited.size(); i++) visited[i] = false;
dfs(a,0);
if(hascycle) return edge;
}
return {};
}
void dfs(int from , int pre){
visited[from] = true ;
for(int go : to[from]){
if(go == pre) continue;
if(!visited[go]) dfs(go,from);
else hascycle = true;
}
}
vector<vector<int>> to;
vector<bool> visited;
bool hascycle ;
};