Leetcode 685

我写的代码比较丑陋,等会再放上来。

 

在树中添加一条附加边,一共会有以下几种情况发生:

 

 

第一种,只有环。这种情况下,把导致环路的边删除即可。由于附加边只有一条,所以环也只能有一个,所以发现环路时,立刻记下当时处理的边。

第二种,有一个节点存在两个父节点,但是没有环路存在。此时删除后来的那个父节点对应那条边即可。

第三种,既有环路,又有冲突。此时需要找出哪个父节点存在于环路中,并将对应边删除。

 

注意图示只是一个简单的示例,你应该意识到某个节点还可以向外延伸出各种边。重点在于,我们需要记录【冲突的两条边】和【导致环路的一条边】。

同时,因为树的父节点只能有一个,所以【导致冲突的边】是不被记录到树结构上的。

 

具体到写代码,我们使用并查集。记父节点数组为 father,当前处理的边为 edges[i],边的两边节点为 <from, to>。

>>> 当 Find(from) == to,我们认为这条边导致了环,记下当前边的 i 为 cycleIndex。

>>> 当 Find(to) != to,我们认为 <from, to> 导致了冲突,并记下当前边的 i 为 conflictIndex。

>>> 如果都不符合,正常地连接两个节点,father[to] = from。

 

经过以上处理,我们就得到了【冲突的两条边】和【导致环路的一条边】。

 

 如果是第一种或者第二种情况,事情就好办多了。关键是,既有冲突又有环的情况下,如何才能知道冲突的两条边谁在环上呢?

我自己采取的办法是,从两条边选出一条,然后递归地求其父节点。

过程中,如果求到了根节点,那么这条边就不必删除。

否则,一定会求到冲突的子节点(也就是上图中的 B 节点)。那么这条边就需要被删除。

 

int p = edges[conflictIndex][0];
bool isConflictEdge = false;            
    
while(father[p] != -1){ // 我个人用-1代表根节点
    p = father[p];
    if(p == edges[conflictIndex][1]){
        isConflictEdge = true;
        break;
    }
}

 

最后,代码的话还是建议看官方题解的代码。

posted on 2020-09-17 23:51  Ricochet!  阅读(134)  评论(0编辑  收藏  举报