在本問題中,有根樹指滿足以下條件的有向圖。該樹只有一個根節點,所有其他節點都是該根節點的後繼。每一個節點只有一個父節點,除了根節點沒有父節點。
輸入一個有向圖,該圖由一個有着N個節點 (節點值不重複1, 2, ..., N) 的樹及一條附加的邊構成。附加的邊的兩個頂點包含在1到N中間,這條附加的邊不屬於樹中已存在的邊。
結果圖是一個以邊組成的二維數組。 每一個邊 的元素是一對 [u, v],用以表示有向圖中連接頂點 u and v和頂點的邊,其中父節點u是子節點v的一個父節點。
返回一條能刪除的邊,使得剩下的圖是有N個節點的有根樹。若有多個答案,返回最後出現在給定二維數組的答案。
示例 1:
輸入: [[1,2], [1,3], [2,3]]
輸出: [2,3]
解釋: 給定的有向圖如下:
1
/ \
v v
2-->3
示例 2:
輸入: [[1,2], [2,3], [3,4], [4,1], [1,5]]
輸出: [4,1]
解釋: 給定的有向圖如下:
5 <- 1 -> 2
^ |
| v
4 <- 3
注意:
二維數組大小的在3到1000範圍內。
二維數組中的每個整數在1到N之間,其中 N 是二維數組的大小。
鏈接:https://leetcode-cn.com/problems/redundant-connection-ii
【思路】
和684. 冗餘連接不同,這一題是有向圖,我們判斷圖中是否存在環的同時,需要判斷是否存在重複的父節點。
因爲題目中必須要刪除一條邊,因此不存在既沒有環又沒有重複父節點的情況。
分三種情況:
1)[[1,2], [1,3], [2,3]]
加入邊[2,3]後,節點3存在重複節點1和2
2)[[1,2], [2,3], [3,4], [4,1], [1,5]]
加入節點[4,1]之後,出現環
3)[[2,1],[3,1],[4,2],[1,4]]
加入[3,1]後,節點1出現重複節點2和3;加入[1,4]後,同時出現環
我們先判斷圖中是否存在重複節點,如果存在重複節點,那麼相鄰的兩條邊必須要刪除其中一條,我們可以假設先刪除一條,緊接着再判斷下刪除後的圖中是否有環即可,如果有,那麼應該刪除另外一條。例如上述3,當節點1出現重複節點的時候,可以刪除[3,1]或者[2,1],假設我們刪除[3,1],然而刪除後圖中存在環,那麼答案應該刪除[2,1]。
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int set[1000000];
int find(int u){//找父節點,由於是有向樹,那麼不要用壓縮路徑,找直系父節點
return u==set[u]?u:find(set[u]);
}
int* findRedundantDirectedConnection(int** edges, int edgesSize, int* edgesColSize, int* returnSize){
int i,j;
int u,v;
int last=-1,tmp=-1,*first=(int*)malloc(sizeof(int)*2),*second=(int*)malloc(sizeof(int)*2);
//以下代碼判斷是否存在重複節點,如果有重複節點,那麼刪除的一定在引起重複節點的兩條邊中。我們標記這兩條邊爲first和second
for(i=1;i<=edgesSize;i++){
set[i]=i;
}
for(i=0;i<edgesSize;i++){//判斷是否有重複的父節點
u=edges[i][0];
v=edges[i][1];
if(set[v]!=v&&u!=set[v]){
first[0]=set[v];first[1]=v;
second[0]=u;second[1]=v;
tmp=i;
break;
}else{
set[v]=u;//v的父節點爲u
}
}
//這裏我們假設刪除second,查看刪除後是否存在環,如果不存在環,那麼刪除second是對滴,否則刪除first
//和上一題類似,查看刪除second後是否存在環,這邊唯一需要注意的是,和無向圖不同,有向圖中父節點(除了根節點)只有一個,因此對於[u,v],直接賦值set[v]=u;即可。
for(i=1;i<=edgesSize;i++){
set[i]=i;
}
for(i=0;i<edgesSize;i++){
if(i==tmp)continue;
u=edges[i][0];
v=edges[i][1];
if(find(u)==find(v)){//存在環
last=i;
}else{
set[v]=u;//直接賦值
}
}
*returnSize=2;
//判斷三種情況
if(tmp!=-1&&last==-1)//存在重複節點,且刪除second之後,不存在環
return second;
else if(tmp!=-1&&last!=-1)//存在重複節點且刪除second之後還存在環,此時不應該刪除second,刪除
return first;
//不存在重複節點,但存在環
return edges[last];
}