leetcode雕蟲小技mediu 684. Redundant Connection

題幹: 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);
        }
    }

 

反思:這題這題主要在輔助函數上寫了一大堆,花了不少時間,應該不是最優雅的寫法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章