LeetCode 1584 题: 连接所有点的最小费用

959 阅读1分钟

题目:

给你一个points 数组,表示 2D 平面上的一些点,其中 points[i] = [xi, yi] 。

连接点 [xi, yi] 和点 [xj, yj] 的费用为它们之间的 曼哈顿距离 :|xi - xj| + |yi - yj| ,其中 |val| 表示 val 的绝对值。

请你返回将所有点连接的最小总费用。只有任意两点之间 有且仅有 一条简单路径时,才认为所有点都已连接。


思路:

标准的最小生成树, Minimum Spanning Trees

两点间的权重值就是曼哈顿距离,

然后 MST, 把每条边的值加起来

常用两种算法:

普里姆算法, Prim 和克鲁斯克尔算法 Kruskal
  • Prim, 从一个点出发,去找其最小边,

再从已连通点出发,保证不成环的情况下,去找此时未连上的最小边

  • Kruskal,把所有边的权重值从小到大排,

从最小边出发,保证不成环的情况下,去找此时未连上的最小边

下面使用 Kruskal,保证不成环,使用并查集

并查集两个操作,查找与合并, Union 和 Find

建立映射,使用 0 到 n - 1 的数组,代表 n 个点,

连一条边,就合并一次

合并就是,代表的数组上的两个值, x = y

还有一个寻根操作


代码:

class Solution{
     struct Distance {
        let from: Int
        let to: Int
        let len: Int
    }
    
    var par: [Int]!
    

    func minCostConnectPoints(_ points: [[Int]]) -> Int {
        var map = [Distance]()
        let rowCount = points.count
        guard rowCount > 1 else {
            return 0
        }
        var i = 0
        while i < rowCount {
            var j = i + 1
            while j < rowCount {
                let val = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                map.append(Distance(from: i, to: j, len: val))
                j += 1
            }
            i += 1
        }
        par = Array(0..<rowCount)
        var result = 0
        i = 0
        let lookup = map.sorted { (lhs, rhs) -> Bool in
            lhs.len < rhs.len
        }
        let count = lookup.count
        while i < count {
            let u = lookup[i].from, v = lookup[i].to, x = find(val: u), y = find(val: v)
            if x != y{
                par[x] = y
                result += lookup[i].len
            }
            i += 1
        }
        return result
    }
    
    
    func find(val x: Int) -> Int{
        if x == par[x]{
            return x
        }
        else{
            par[x] = find(val: par[x])
            return par[x]
        }
    }
}