力扣 1334.阈值距离内邻居最少的城市

2023-11-23

难度 中等

原题

1334. 阈值距离内邻居最少的城市 - 力扣(LeetCode)

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

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

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

示例 1:

力扣 1334.阈值距离内邻居最少的城市_第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] 
城市 0 和 3 在阈值距离 4 以内都有 2 个邻居城市,但是我们必须返回城市 3,因为它的编号最大。

示例 2:

力扣 1334.阈值距离内邻居最少的城市_第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 个邻居城市。
弗洛伊德算法及原理 

        使用弗洛伊德算法邻接矩阵

        首先讲一下弗洛伊德算法和邻接矩阵

力扣 1334.阈值距离内邻居最少的城市_第3张图片

         邻接矩阵是一个对称矩阵,长和宽都和图的顶点数目相同,该处的数字为两个顶点之间的距离,对于不可到达的顶点距离一般设置为最大值,无向图是对称矩阵

矩阵dist
  0    3 INF INF
  3    0   1   4
INF    1   0   1
INF    4   1   0

        从这个矩阵中可以清晰地看到目标点之间的距离,这里我们可以尝试获取顶点0和顶点1的一个距离,对于直接连接的顶点直接取dist [ 0 ][ 1 ],而对于间接连接的顶点,比如顶点0和顶点3,距离dist[ 0 ][ 3 ]为INF,但并非不可到达,可以连续经过其他点到达顶点3,我们可以从顶点0先到达第一站,任意一个和顶点0直接连接的顶点这里只有1 dist[ 1 ],所以我们前往顶点1,此时就变成了从顶点1到达顶点3 dist[ 1 ][ 3 ],而顶点1可以直接到达顶点3。

        或者我们到达顶点1后来到第二站,第二站一般不取走过的站,这里可以选择顶点2 dist[ 1 ][ 2 ],然后再从顶点2到达顶点3 dist[ 2 ][ 3 ]。

        对于上述两条路线,除了经过的站点的数量,移动的距离也受到了影响,第一条路线的长度为 dist[ 0 ][ 1 ]+dist[ 1 ][ 3 ]=1+4=5

        另一条为dist[ 0 ][ 1 ]+dist[ 1 ][ 2 ]+dist[ 2 ][ 3 ] = 1+1+1=3

        显然我们可以根据需求寻找我们所需要的走法,这题和弗洛伊德算法一样求的是最短路径 

弗洛伊德算法状态转移方程为

dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j])

        i,j,k这个三个参数可能不好理解,至少我不怎么理解,那么来模拟一下寻找最短路径

        回到之前的图和邻接矩阵,其中任何dist[i][i]都是0,任何dist[i][j]都等于dist[j][i]

力扣 1334.阈值距离内邻居最少的城市_第4张图片

矩阵dist
  0    3 INF INF
  3    0   1   4
INF    1   0   1
INF    4   1   0

        比如我们打算获取顶点1到顶点3的最小距离,需要不断从各种路线取最小值,最后的dist[1][3]即是1和3距离的最小值

第一步:dist[1][3] = min(dist[1][3],dist[1][0]+dist[0][3]),即是dist[i][j] = min(dist[i][j],dist[i][k]+dist[k][j]),min中的两个参数一个是等号左边的数字,用于迭代最小值,第二个参数就是取两个顶点都连接或者间接连接的顶点的距离之和

    力扣 1334.阈值距离内邻居最少的城市_第5张图片

回到第一步,dist[1][3] = min(dist[1][3],dist[1][0]+dist[0][3]),因为dist[0][3]是INF,所以跳过,最小值还是初始的4

第二步:dist[1][3] = min(dist[1][3],dist[1][1]+dist[1][3]),啥也没发生

第三步:dist[1][3] = min(dist[1][3],dist[1][2]+dist[2][3]),可以算出来后者更小

第四步:dist[1][3] = min(dist[1][3],dist[1][3]+dist[3][3]),啥也没发生

最后得到的最小的dist[1][3]就是dist[1][2]+dist[2][3],也就是2

所以这三个参数就很简单了,i和j表示dist[i][j]的值,k就是中间点的位置,虽然是个n*n矩阵但是只有n个值,这里的k就是表示第k个值

看似已经没问题了,但是不确定dist[2][3]的值是否是最小,dist[2][3]是否存在类似dist[2][1]+dist[1][3]这种值,虽然这里更大,但是不排除其他情况有更小的值,所以还是要从dist[0][0]到dist[3][3]取最小值,也就是动态规划

解法
        public int findTheCity(int n, int[][] edges, int distanceThreshold) {
            int[][] matrix = new int[n][n];//创建矩阵
            for (int i = 0; i < n; i++) {//初始化矩阵
                Arrays.fill(matrix[i],Integer.MAX_VALUE);
                //对于不可到达的矩阵取最大值用于校验,走到了就是死路,只能换路
                //因为这个矩阵是整型矩阵所以就不要填写别的类型了
                matrix[i][i] = 0;//自己到自己的距离就是0
            }
            for (int[] edge:edges){
                matrix[edge[0]][edge[1]] = edge[2];//不断将edges中的数据填到矩阵中
                matrix[edge[1]][edge[0]] = edge[2];//对称换一下0和1的位置就够了
            }
            for (int i = 0; i < n; i++)//第i行的值
                for (int j = 0; j < n; j++)//第j列的值
                    for (int k = 0; k < n; k++)//然后从第一个顶点开始加
                        if (matrix[j][i]!=Integer.MAX_VALUE&&
                            matrix[i][k]!=Integer.MAX_VALUE)//不能走到死路
                            matrix[j][k] = Math.min(matrix[i][j],matrix[j][i]+matrix[i][k]);
                            //没走到死路即对比值,这个循环会使用所有的顶点作为中继点,然后会逐个替换这个值
            //循环结束之后整个矩阵已经成了一个新的矩阵,矩阵的每个点的值都是这个点的两个顶点的最小值
            int min = Integer.MAX_VALUE;
            int res = -1;
            for (int i = 0; i < n; i++) {//遍历矩阵,同时找最小值
                int count = 0;
                for (int j = 0; j < n; j++) {
                    if (matrix[i][j]<=distanceThreshold)
                        count++;//找到从顶点i到达其他顶点的距离小于等于目标距离的路线数量
                }
                if (count<=min){
                    min = count;
                    res = i;//迭代最小值
                }
            }
            System.out.println("the world!");
            return res;
        }

你可能感兴趣的:(leetcode,算法,矩阵,数据结构)