问题来源
Some explanation
之所以跳过Redundant Connection I是因为1题目有瑕疵并且I的题面中也告知了更新版本II(难度也提升到了Hard)所以就直接写II了
问题描述
In this problem, a rooted tree is a directed graph such that, there is exactly one node (the root) for which all other nodes are descendants of this node, plus every node has exactly one parent, except for the root node which has no parents.
The given input is a directed graph that started as a rooted tree with N nodes (with distinct values 1, 2, …, N), with one additional directed edge added. The added edge has two different vertices chosen from 1 to N, and was not an edge that already existed.
The resulting graph is given as a 2D-array of edges. Each element of edges is a pair [u, v] that represents a directed edge connecting nodes u and v, where u is a parent of child v.
Return an edge that can be removed so that the resulting graph is a rooted tree of N nodes. If there are multiple answers, return the answer that occurs last in the given 2D-array.
Example 1:
Input: [[1,2], [1,3], [2,3]]
Output: [2,3]
Explanation: The given directed graph will be like this:
1
/ \
v v
2-->3
Example 2:
Input: [[1,2], [2,3], [3,4], [4,1], [1,5]]
Output: [4,1]
Explanation: The given directed graph will be like this:
5 <- 1 -> 2
^ |
| v
4 <- 3
Note:
- The size of the input 2D-array will be between 3 and 1000.
- Every integer represented in the 2D-array will be between 1 and N, where N is the size of the input array.
问题分析
题目的意思十分明显,就是找出一个有根的有向图中一条多余的边。如果把此图看作无向图的话,实际上这条多余的边便是构成图中环的某一条边之一,但此时是有向图,所以我们需要分情况讨论:
1. 有入度大于2的节点但无环路。通过题目描述我们知道,除根节点外,所有节点的入度都应该为1。所以一旦存在入度2的节点,则指向该节点的边必有一条为多余,删除最后出现的边即可。注意此时是图是无环的。例:
[[1,2],[1,3],[2,3]]
2. 无入度大于2的节点但有环路。那就是所有节点的入度均为1的情况,此时只需删除最后一条边即可。例:
[[1,2],[2,3],[3,1]]
3. 既有入度大于2的节点又有环。例:
[[1,2], [2,3], [3,4], [4,1], [5,1]].
这种情况是此题的难点所在。对于这种情况,我的解决方案是逆推求环。即,对于指向该入度为2的节点u的边e1,e2(由题目可知多余的边只会有一条),逆方向行走,看能否返回u,如果能返回则删除对应边即可。即同时解决了环与入度的问题
解决代码
class Solution(object):
def findRedundantDirectedConnection(self, edges):
"""
:type edges: List[List[int]]
:rtype: List[int]
"""
tmp = {}
tmp_cir = []
suspect = -1
for edge in edges:
if tmp.get(edge[1]):
suspect = edge[1]
tmp[edge[1]].append(edge[0])
else:
tmp[edge[1]] = [edge[0]]
suspect_edge = []
for edge in edges:
if edge[0] in tmp_cir and edge[1] in tmp_cir:
suspect_edge.append(edge)
else:
tmp_cir.extend(edge)
if suspect == -1:
return suspect_edge[len(suspect_edge)-1]
if len(suspect_edge) == 0:
return [tmp[suspect], suspect]
for e in tmp[suspect]:
if (can_reach(suspect, e, tmp)):
return [e,suspect]
return [tmp[suspect][1], suspect]
'''
最后此句的目的是解决由于我前面代码对于环的判断是基于无向图的判断而造成对于某些无环图的误判,如[[1,2],[1,3],[2,3]]
'''
def can_reach(s,e,tmp):
while type(tmp.get(e)) == list:
e = tmp[e][0]
if (s == e):
return True
return False