在 Java 中实现 Kruskal 算法的联合查找算法以找到最小生成树

我正在尝试解决以下 Leetcode 问题 (https://leetcode.com/problems/connecting-cities-with-minimum-cost),我的方法是使用 Kruskal 算法使用 Union-Find 从输入图中找出最小生成树 (MST) 的总权重数据结构。但是,我的代码在线通过了51/63的测试用例,在下面的测试用例中返回了错误的结果,由于输入图太大,这太难调试了。

50
[[2,1,22135],[3,13746],[4,3,37060],[5,2,48513],[6,49607],[7,97197],[8,95909],[9,82668],[10,48372],[11,4,17775],[12,6017],[13,51409],[14,12884],[15,7,98902],[16,14,52361],[17,8,11588],[18,12,86814],[19,17,49581],[20,41808],[21,11,77039],[22,10,80279],[23,16,61659],[24,89390],[25,24,10042],[26,78278],[27,15,30756],[28,6,2883],[29,3478],[30,29321],[31,47542],[32,20,35806],[33,26531],[34,16321],[35,27,82484],[36,55920],[37,21253],[38,23,90537],[39,83795],[40,36,70353],[41,34,76983],[42,63416],[43,39590],[44,9,86794],[45,31968],[46,19,32695],[47,40287],[48,27993],[49,86349],[50,52080],65829],45,87517],96130],50,3601],2017],44,4118],29,93146],[1,56934],43,5984],22,13404],28,66475],93296],71637],37,88398],56056],[2,79170],55496],46,14494],25143],59961],49,58317],38,33783],19762],41,69590],26831],53060],7570],42,98814],96014],94702],18873],43666],40,69729],25,28548],19305],39749],48,43826],38867],56073],51377],73530],67511],76774],21,21673],72219],9568],66173],93641],87301],41318],25717],3006],85003],33961],56248],31,10007],23971],24448],39,87474],3371],18,26351],86238],73207],75438],47,35394],32,69991],87955],85693],50456],59182],58363],58494],73017],88526],48361],59995],66426],29387],80738],63014],90635],36051],1515],72665],85644],70642],88771],79583],45432],95097],96934],35,79611],26,71147],57109],67266],15913],30,44704],46266],94508],45742],56618],79396],78005],94010],4417],7762],13,12161],60013],6891],63893],74832],3562],47831],82689],71961],82402],33,38732],24131],96267],81067],41426],68768],78243],77645],96335],30726],34801],22953],34898],32324],18539],59737],67994],25013],25671],57657],83932],24122],851],70508],53629],34945],64478],75022],55721],84838],6103],11497],22278],56616],18681],56358],13360],59846],36311],63309],30207],22241],94146],62994],32450],8063],56772],21224],40328],48426],39752],96892],73566],43360],51956],5710],72496],9207],39474],82661],84860],25992],33166],11721],68623],98119],3644],84611],52972],60307],44224],89857],21705],12562],32209],26285],80956],51968],36399],37774],24687],55470],69677],6826],38561]]

我无法理解为什么我的代码会在测试用例中失败,因为我相信我正在正确地实施 Kruskal 算法的步骤:

  1. 按权重的递增顺序对连接进行排序。
  2. 通过遍历排序列表中的每个连接并选择该连接(如果它不会导致 MST 中的循环)来构建 MST。

以下是我的 Java 代码:

class UnionFind {
    // parents[i] = parent node of node i.
    // If a node is the root node of a component,we define its parent
    // to be itself.
    int[] parents;
    
    public UnionFind(int n) {
        this.parents = new int[n];
        
        for (int i = 0; i < n; i++) {
            this.parents[i] = i;
        }
    }
    
    // Merges two nodes into the same component.
    public void union(int node1,int node2) {
        int node1Component = find(node1);
        int node2Component = find(node2);
        
        this.parents[node1Component] = node2Component;
    }
    
    // Returns the component that a node is in.
    public int find(int node) {
        while (this.parents[node] != node) {
            node = this.parents[node];
        }
        
        return node;
    }
}

class Solution {
    public int minimumCost(int n,int[][] connections) {
        UnionFind uf = new UnionFind(n + 1);
        
        // Sort edges by increasing cost.
        Arrays.sort(connections,new Comparator<int[]>() {
            @Override
            public int compare(final int[] a1,final int[] a2) {
                return a1[2] - a2[2];
            }
        });
        
        int edgeCount = 0;
        int connectionIndex = 0;
        int weight = 0;
        
        // Greedy algorithm: Choose the edge with the smallest weight 
        // which does not form a cycle. We know that an edge between 
        // two nodes will result in a cycle if those nodes are already 
        // in the same component.
        for (int i = 0; i < connections.length; i++) {
            int[] connection = connections[i];
            int nodeAComponent = uf.find(connection[0]);
            int nodeBComponent = uf.find(connection[1]);
            
            if (nodeAComponent != nodeBComponent) {
                weight += connection[2];
                edgeCount++;
            }
            
            if (edgeCount == n - 1) {
                break;
            }
        }
        
        // MST,by definition,must have (n - 1) edges.
        if (edgeCount == n - 1) {
            return weight;
        }
        return -1;
    }
}
yyb4051 回答:在 Java 中实现 Kruskal 算法的联合查找算法以找到最小生成树

正如@geobreze 所说,我忘记将节点 A 和节点 B 的组件(不相交集)联合起来。以下是更正后的代码:

if (nodeAComponent != nodeBComponent) {
    uf.union(nodeAComponent,nodeBComponent);
    weight += connection[2];
    edgeCount++;
}
本文链接:https://www.f2er.com/3199.html

大家都在问