運行時間排名不太好。
大體思路:
①先用並查集求出環中的某一個點,依次作爲搜索的起點:
成環的要求:要merge
的兩個節點,它們已經在一個並查集裏面了。
ufs.find(y)==ufs.find(x)
②
用上面求出的根節點作爲搜索起點,dfs
遍歷整棵樹。注意不能走回頭路。
③
當再次搜索到根節點的時候,說明成環,立即結束遞歸。
④
爲了方便最後的查詢(O(log n)),用set
記錄下搜索路徑上的點,回溯時,注意刪除。
⑤
最後逆序遍歷題給的邊集,若邊的兩個點,都在集合裏,輸出。
整體時間複雜度:
struct UFS{
int f[1010];
UFS(){
for(int i=0;i<1010;i++){
f[i] = i;
}
}
int find(int x){
return x==f[x]?x:f[x]=find(f[x]);
}
void merge(int x,int y){
f[find(x)] = find(y);
}
};
//先用並查集找環裏面的某一個節點
class Solution {
public:
int graph[1010][1010] = {0};
int n,root;
vector<int> findRedundantConnection(vector<vector<int>>& edges) {
n = edges.size();
UFS ufs;
for(auto edge:edges){
int x = edge[0];
int y = edge[1];
graph[x][y] = graph[y][x] = 1;
if(ufs.find(y)==ufs.find(x)){
root = x;
break;
}
ufs.merge(x,y);
}
set<int> res;
dfs(root,0,res);
// cout<<root<<endl;
vector<int> ans;
for(int i=n-1;i>=0;i--){
auto edge=edges[i];
int x = edge[0];
int y = edge[1];
if(res.count(x) && res.count(y)){
ans.push_back(min(x,y));
ans.push_back(max(x,y));
break;
}
}
return ans;
}
bool dfs(int x,int last,set<int>&res){
// cout<<x<<endl;
if(x==root && last!=0){
return true;
}
res.insert(x);
for(int y=1;y<=n;y++){
if(graph[x][y] && y!=last){
if(dfs(y,x,res)){
return true;
}
res.erase(y);
}
}
return false;
}
};
更爲優雅的做法依次遍歷邊集,如果x,y的代表元已經相同,那麼說明這時候再去merge(x,y)
,相當於成環。
如果沒有,merge(x,y)。
注:題目要求,若有多解,選擇題給數據中的最後一個數據。
所以,直接順次遍歷就好。
class Solution {
public:
int f[1010];
vector<int> findRedundantConnection(vector<vector<int>>& edges) {
for(int i=1;i<=edges.size();i++){
f[i] = i;
}
vector<int> ans;
for(auto edge:edges){
int x = edge[0];
int y = edge[1];
if(find(x)==find(y)){
ans = edge;
}else{
merge(x,y);
}
}
return ans;
}
int find(int x){
return x==f[x]?x:f[x]=find(f[x]);
}
void merge(int x,int y){
f[find(x)] = find(y);
}
};