算法初探LeetCode-阈值距离内邻居最少的城市

72 阅读2分钟

LeetCode1334. 阈值距离内邻居最少的城市

有 n 个城市,按从 0 到 n-1 编号。给你一个边数组 edges,其中 edges[i] = [fromi, toi, weighti] 代表 fromi 和 toi 两个城市之间的双向加权边,距离阈值是一个整数 distanceThreshold

返回能通过某些路径到达其他城市数目最少、且路径距离 最大 为 distanceThreshold 的城市。如果有多个这样的城市,则返回编号最大的城市。

注意,连接城市 i 和 j 的路径的距离等于沿该路径的所有边的权重之和。 示例 1:

输入: n = 4, edges = [[0,1,3],[1,2,1],[1,3,4],[2,3,1]], distanceThreshold = 4
输出: 3
解释: 城市分布图如上。
每个城市阈值距离 distanceThreshold = 4 内的邻居城市分别是:
城市 0 -> [城市 1, 城市 2] 
城市 1 -> [城市 0, 城市 2, 城市 3] 
城市 2 -> [城市 0, 城市 1, 城市 3] 
城市 3 -> [城市 1, 城市 2] 
城市 03 在阈值距离 4 以内都有 2 个邻居城市,但是我们必须返回城市 3,因为它的编号最大。

示例 2:

输入: n = 5, edges = [[0,1,2],[0,4,8],[1,2,3],[1,4,2],[2,3,1],[3,4,1]], distanceThreshold = 2
输出: 0
解释: 城市分布图如上。 
每个城市阈值距离 distanceThreshold = 2 内的邻居城市分别是:
城市 0 -> [城市 1] 
城市 1 -> [城市 0, 城市 4] 
城市 2 -> [城市 3, 城市 4] 
城市 3 -> [城市 2, 城市 4]
城市 4 -> [城市 1, 城市 2, 城市 3] 
城市 0 在阈值距离 2 以内只有 1 个邻居城市。

提示:

  • 2 <= n <= 100
  • 1 <= edges.length <= n * (n - 1) / 2
  • edges[i].length == 3
  • 0 <= fromi < toi < n
  • 1<=weighti, distanceThreshold<=1041 <= weighti, distanceThreshold <= 10^4
  • 所有 (fromi, toi) 都是不同的。

思路分析

题目要求计算路径距离最大为 distanceThreshold的情况下可以到达的城市数目最少的城市,需要计算每一对城市之间的最短距离,然后统计每个城市可以到达的路径距离最大为 distanceThreshold的城市数目。

当有 n个城市时,需要分别将 n 个城市作为起点城市,使用 Dijkstra 算法得到从起点城市到每个城市的最短距离。

对于每个起点城市,执行 n 次循环。每次循环时,从尚未确定最短距离的城市中找到最短距离最小的城市,将该城市的状态更新为确定最短距离,并使用该城市的最短距离更新该城市的所有相邻且尚未确定最短距离的城市的最短距离。由于每次循环都能确定一个城市的最短距离,因此经过 n次循环之后即可得到每个城市的最短距离。

寻找最短距离最小的城市有两种做法,第一种做法是枚举所有尚未确定最短距离的城市,第二种做法是维护小根堆。

算法代码

public int findTheCity(int n, int[][] edges, int distanceThreshold) {
    List < int[] > [] adjacentArr = new List[n];
    for (int i = 0; i < n; i++) {
        adjacentArr[i] = new ArrayList < int[] > ();
    }
    for (int[] edge: edges) {
        int city0 = edge[0], city1 = edge[1], weight = edge[2];
        adjacentArr[city0].add(new int[] {
            city1, weight
        });
        adjacentArr[city1].add(new int[] {
            city0, weight
        });
    }
    int leastCity = -1, leastNeighbors = Integer.MAX_VALUE;
    for (int i = n - 1; i >= 0; i--) {
        int neighbors = dijkstra(adjacentArr, i, distanceThreshold);
        if (leastNeighbors > neighbors) {
            leastCity = i;
            leastNeighbors = neighbors;
        }
    }
    return leastCity;
}

public int dijkstra(List < int[] > [] adjacentArr, int source, int distanceThreshold) {
    int n = adjacentArr.length;
    int[] distances = new int[n];
    Arrays.fill(distances, Integer.MAX_VALUE / 2);
    distances[source] = 0;
    boolean[] visited = new boolean[n];
    for (int i = 0; i < n; i++) {
        int curr = -1;
        for (int j = 0; j < n; j++) {
            if (!visited[j] && (curr < 0 || distances[curr] > distances[j])) {
                curr = j;
            }
        }
        visited[curr] = true;
        for (int[] adjacent: adjacentArr[curr]) {
            int next = adjacent[0], weight = adjacent[1];
            distances[next] = Math.min(distances[next], distances[curr] + weight);
        }
    }
    int neighbors = 0;
    for (int i = 0; i < n; i++) {
        if (i == source) {
            continue;
        }
        if (distances[i] <= distanceThreshold) {
            neighbors++;
        }
    }
    return neighbors;
}

结果详情

Snipaste_2023-06-29_16-30-16.png

算法复杂度

  • 空间复杂度:O(n)O(n)
  • 时间复杂度:O(n2)O(n^2)

掘金(JUEJIN)一起进步,一起成长!