一、欧拉路径是什么
欧拉路径就是一条能够不重不漏的经过图上的每一条边的路径,即经常说的一笔画问题,就是一笔将图上所有的点连接起来,不重复某一个节点也不遗漏某一个节点。若这条路径的起点和终点相同,则称这条路径为欧拉回路。
一个图存在欧拉路径需要满足以下几个条件:
- 图是连通图,即不存在断连的点。
- 若是无向图,则这个图的度数为奇数的点必须是0或2;若是有向图,要么所有点的入度和出度相等,要么有且只有两个点的入度分别比出度大1或者小1。
二、查找欧拉路径算法
1.Hierholzer算法流程
- 对于无向图,判断度数为奇数点的个数,若为0,则设任意一点为起点,若为2,则从这两个点中任意取一个作为起点;对于有向图,判断入度和出度不同的点的个数,若为2,则设入度比出度小1的点为起点,另一个点为终点。
- 从起点开始进行递归,对于当前节点x,扫描与x相连的所有边,当扫描到某一条边(x,y)时,删除该条边,并递归y,扫描完所有边后,将x加入队列。
- 倒序输出答案队列。
2.实际应用(LeetCode 5932 – 270周赛 题目四)
按照Hierholzer算法流程,代码如下:
class Solution {
//每一个节点的相连节点
Map<Integer,List<Integer>> neigh;
List<Integer> ret;
public int[][] validArrangement(int[][] pairs) {
int len = pairs.length;
neigh = new HashMap<>();
//每一个节点的入度
Map<Integer,Integer> inDeg = new HashMap<>();
//每一个节点的出度
Map<Integer,Integer> outDeg = new HashMap<>();
for(int[] p : pairs){
g.putIfAbsent(p[0] , new ArrayList<>());
g.get(p[0]).add(p[1]);
inDeg.put(p[1] , inDeg.getOrDefault(p[1], 0) + 1);
outDeg.put(p[0] , outDeg.getOrDefault(p[0] , 0) + 1);
}
//起始节点
int start = -1;
//寻找起始节点 如果出度比出度大一 则该节点就可以被当做start
for(int key : outDeg.keySet()){
if(outDeg.get(key) - inDeg.getOrDefault(key , 0) == 1){
start = key;
break;
}
}
//如果不存在出度比入度大一的节点 则该图是一个环 任意一个节点都可以当做起始节点
if(start == -1){
start = pairs[0][0];
}
ret = new ArrayList<>();
//遍历
dfs(start);
//转换为答案
int[][] ans = new int[len][2];
for(int i = len ; i > 0 ; i--){
ans[len-i][0] = ret.get(i);
ans[len-i][1] = ret.get(i-1);
}
return ans;
}
void dfs(int start){
//获取相邻的节点
List<Integer> list = neigh.getOrDefault(start , new ArrayList<>());
//每一个节点继续遍历 直到没有相邻边 则可以添加到res
while(list.size() > 0){
int x = list.remove(list.size()-1);
dfs(x);
}
ret.add(start);
}
}
总结
这就是欧拉路径的求法,其中欧拉路径需要满足的条件以及上述Hierholzer算法需要熟记。
leetcode332题同样也是欧拉路径问题,只不过是上述问题的退化版。
参考连接:欧拉路径详解
如有错误,恳请大家批评指证,日拱一卒,功不唐捐。