题目描述:
给你一个无向图,整数 n
表示图中节点的数目,edges
数组表示图中的边,其中 edges[i] = [ui, vi]
,表示 ui
和 vi
之间有一条无向边。
一个 连通三元组 指的是 三个 节点组成的集合且这三个点之间 两两 有边。
连通三元组的度数 是所有满足此条件的边的数目:一个顶点在这个三元组内,而另一个顶点不在这个三元组内。
请你返回所有连通三元组中度数的 最小值 ,如果图中没有连通三元组,那么返回 -1
。
示例与输入:
输入:n = 6, edges = [[1,2],[1,3],[3,2],[4,1],[5,2],[3,6]] 输出:3 解释:图中连通三元组为1-2-3,该连通三元组的度数为边:1-4,2-5,3-6,故该三元组度数为3。由于图中不存在其它三元组,所以该无向图的最小度数为3。
解题思路:
我们容易根据edges计算出每个节点的连接边数量,只需遍历一遍edges即可。图中的点、边关系可列为下表:
节点 | 该节点连接其它节点 |
node-1 | 2,3,4 |
node-2 | 1,3,5 |
node-3 | 1,2,6 |
node-4 | 1 |
node-5 | 2 |
node-6 | 3 |
如果知道(1,2,3)三个点构成三元组,那么节点1的度数就是节点1连接的边的数量减2。以此类推,可以知道节点2的度数,节点3的度数,三个节点度数之和就是该三元组的度数。
所以,已知一个三元组,怎么求其度数弄清楚之后,接下来的任务就是求出所有三元组。这里的方法类似于DFS。创建一个栈stack,stack内放入一个节点 i 的所有连接结点;随后,该stack内的节点依次弹出,每弹出一个节点 j ,就寻找该弹出节点所连接的所有节点,放进一个list中。比对list和stack的剩余元素是否存在交集,如果有交集并记为k,则 i , j , k就构成一个三元组。
接下来只要寻找到三元组中度数的最小值即可。
代码--python3:
class Solution:
def minTrioDegree(self, n: int, edges: list) -> int:
edges_dict = {}
for i in edges: # 创建一个字典,遍历edges,把每个节点连接的节点以list结构记下
edges_dict.setdefault(i[0], list()).append(i[1])
edges_dict.setdefault(i[1], list()).append(i[0])
# access_node记录访问过的节点,避免重复找三元组
tri_degree, access_node = [], set()
for i in edges_dict:
# 调用edges_dict中的value,但不想改变原数据(后面用于求度数),用一次深拷贝
stack = set(copy.deepcopy(edges_dict[i])).difference(access_node) # 去重
if len(stack) <= 1: # 一个节点若连接的节点都不够两个就别凑热闹了,肯定构不成三元
continue
access_node.add(i)
while stack:
a = stack.pop()
b = set(edges_dict[a]).intersection(set(stack)) # set求交集,空间换时间
if b:
for k in b:
tri_degree.append((i,a,k))
ans = -1
for i in tri_degree: # 求度数
temp = len(edges_dict[i[0]])+len(edges_dict[i[1]])+len(edges_dict[i[2]])-6
if ans == -1:
ans = temp
else:
ans = min(ans, temp)
return ans
改进:
1. set是很方便,但其底层去重实际用的是红黑树,并且set会改变原list中的顺序。其高效的同时空间复杂度会比遍历要高很多。
2. 如果需要频繁查询,而非增、删、改,可以使用哈希表,增加效率(近似看作较大的O(1))。当然哈希表创建的过程要比array、linklist等结构时间更多。根据需求采用不同的数据结构。