题干: https://leetcode.com/problems/redundant-connection/
这题地思路不难,就是在边中找环,取环中所有边中index最大者即可。
问题是怎么找环呢?我的大体思路是从任意一个顶点开始尝试,使用回溯法,只要发现环路,立即停止并输出该环
说是这么说,具体怎么做呢?亲自试了下写起来并没有那么容易。
首先得收集一个数据结构,每个顶点对应哪些边,用一个Map来表示。
然后对每条边进行尝试时,需要做一些判断,该边是否有访问过,没 访问过则加入选边列表,递归进行,每次递归都要首先判断,目前已选的边是否已经构成环路,若是,则进行输出赋值。还要注意每次选完边后,你得知道当前最后跑到的节点是谁,否则你不知道洗一次选择从哪里分叉,所以需要写个小的辅助函数来根据已选边确定最后节点,方法是最后边的两个节点减去倒数第二条边的两个节点即可(差集)。
代码如下:
public int[] findRedundantConnection(int[][] edges) { // collect edges to map of int->list of edge index Map<Integer, List<Integer>> vertexEdgeIndexMap = new HashMap<>(); for(int i=0;i<edges.length;i++){ add2map(vertexEdgeIndexMap, edges[i][0], i); add2map(vertexEdgeIndexMap, edges[i][1], i); } for(Integer vertex: vertexEdgeIndexMap.keySet()){ // if vertex in circle, return the max index edge in the circle, else return -1 int code = checkVertexInCircle(vertex, vertexEdgeIndexMap, edges); if(code==-1){ continue; }else{ return edges[code]; } } // this should never happen, because we can guarantee the input contains loop return new int[0]; } private int checkVertexInCircle(int vertex, Map<Integer, List<Integer>> vertexEdgeIndexMap, int[][] edges){ List<Integer> edgeChoices = new ArrayList<>(); List<Integer> circleEdges = new ArrayList<>(); traverse(vertex, vertexEdgeIndexMap, edges, edgeChoices, circleEdges); //可能本顶点有环,也可能无环 if(circleEdges.size()>0){ return circleEdges.stream().max(Integer::compare).get(); }else{ return -1; } } // 假设arr1长度为2 private int exclude(int[] arr1, int[] arr2){ List<Integer> tt = Arrays.stream(arr2).boxed().collect(Collectors.toList()); return tt.contains(arr1[0])?arr1[1]:arr1[0]; } private boolean isCircle(List<Integer> edgeChoices, int[][] edges){ int startVertex = exclude(edges[edgeChoices.get(0)], edges[edgeChoices.get(1)]); int endVertex = exclude(edges[edgeChoices.get(edgeChoices.size()-1)], edges[edgeChoices.get(edgeChoices.size()-2)]); if(startVertex==endVertex){ return true; } return false; } private void traverse(int vertex, Map<Integer, List<Integer>> vertexEdgeIndexMap, int[][] edges, List<Integer> edgeChoices, List<Integer> circleEdges){ if(edgeChoices.size()>=3){ // if edgeChoices forms a circle, set circleEdges once for all and return if(isCircle(edgeChoices, edges)){ // circleEdges = new ArrayList<>(edgeChoices); circleEdges.clear(); for(Integer e: edgeChoices){ circleEdges.add(e); } return; } } List<Integer> choices = new ArrayList<>(); if(edgeChoices.size()<1){ choices = vertexEdgeIndexMap.get(vertex); }else{ // find the final point x int x; if(edgeChoices.size()==1){ x = (edges[edgeChoices.get(0)][0]==vertex?edges[edgeChoices.get(0)][1]:edges[edgeChoices.get(0)][0]); }else{ int[] pointsInLast = edges[edgeChoices.get(edgeChoices.size()-1)]; int[] pointsInSecondLast = edges[edgeChoices.get(edgeChoices.size()-2)]; x = exclude(pointsInLast, pointsInSecondLast); } choices = vertexEdgeIndexMap.get(x); } for(Integer c: choices){ if(!edgeChoices.contains(c)){ edgeChoices.add(c); traverse(vertex, vertexEdgeIndexMap, edges, edgeChoices, circleEdges); edgeChoices.remove(edgeChoices.size()-1); } } } private void add2map(Map<Integer, List<Integer>> vertexEdgeIndexMap, Integer key, Integer val){ if(vertexEdgeIndexMap.get(key)!=null){ vertexEdgeIndexMap.get(key).add(val); }else{ List<Integer> eIndexs = new ArrayList<>(); eIndexs.add(val); vertexEdgeIndexMap.put(key, eIndexs); } }
反思:这题这题主要在辅助函数上写了一大堆,花了不少时间,应该不是最优雅的写法。