【Leetcode】1245. Tree Diameter

题目地址:

https://leetcode.com/problems/tree-diameter/

给定一个有树性质的无向图,求其直径。直径的意思是图中距离最远的两个顶点之间的距离。

先用邻接表建图。接着从任意一个点 v v v出发对图进行DFS,找到离 v v v最远的顶点 u u u,然后再从 u u u出发对图进行DFS,求出离 u u u最远的顶点的距离即可。

算法正确性证明:
只需证明第一次DFS搜到的最远的点一定可以作为直径的一个端点即可。对图的顶点个数做归纳。如果图只有 1 1 1 2 2 2个顶点结论显然成立。接下来假设图有 n n n个顶点,并且第一次DFS是从 v v v开始搜的。如果 v v v位于某条直径上,那么直径的一个端点显然就是离 v v v的最远的点之一,结论正确。如果 v v v不位于任何一条直径上,那么对于去掉 v v v后产生的若干连通分支,必然有一个完全包含直径,而且这个直径也是该连通块的直径。设 u u u v v v的在该连通块里的邻接点,那么这个连通块的顶点个数比原图小,由归纳假设,这个连通块的与 u u u最远的点 w w w可以作为这个连通块的一条直径的端点。而从 v v v开始DFS的时候,当走到了含 u u u的连通分支的时候, w w w就会被搜到。下面证明,不会有别的顶点比 w w w v v v更远。首先 u u u所在的连通块不会有这样的点,因为这个连通块里离 v v v最远的点就是离 u u u最远的点,而由归纳假设 w w w就是离 u u u最远的点。如果别的连通块里有离 v v v更远的点,比如说是 z z z,那么这个点到 v v v再到 w w w形成的路径要比直径(设直径是为 w → w ′ w\to w' ww)更长(这个是可以证明的,设 f f f是路径长度函数,则 f ( z , w ) = f ( z , v ) + f ( v , w ) > 2 f ( v , w ) ≥ f ( v , w ) + f ( v , w ′ ) > f ( w , w ′ ) f(z,w)=f(z,v)+f(v,w)>2f(v,w)\ge f(v,w)+f(v,w')>f(w,w') f(z,w)=f(z,v)+f(v,w)>2f(v,w)f(v,w)+f(v,w)>f(w,w)),这就矛盾了。所以 w w w是整个图离 v v v最远的点之一。证明完毕。

代码如下:

import java.util.*;

public class Solution {
    public int treeDiameter(int[][] edges) {
        Map<Integer, List<Integer>> graph = new HashMap<>();
        for (int[] edge : edges) {
            graph.putIfAbsent(edge[0], new ArrayList<>());
            graph.putIfAbsent(edge[1], new ArrayList<>());
            graph.get(edge[0]).add(edge[1]);
            graph.get(edge[1]).add(edge[0]);
        }
        
        boolean[] visited = new boolean[edges.length + 1];
        // dis是一个长度为2的数组,dis[0]存的是DFS距离第0层递归的cur最远的顶点编号,dis[1]存的是距离
        int[] dis = {0, 0};
        
        // 从0出发进行DFS,将dis更新为距离0最远的顶点编号和距离
        dfs(0, 0, dis, graph, visited);
        
        // 将visited重新标为false,再从dis[0]开始DFS
        Arrays.fill(visited, false);
        dfs(dis[0], 0, dis, graph, visited);
        // 返回距离dis[0]最远的顶点的距离
        return dis[1];
    }
    
    // 从cur出发,curDis指递归的深度,
    // dis是一个长度为2的数组,dis[0]存的是距离第0层递归的cur最远的顶点编号,dis[1]存的是距离
    private void dfs(int cur, int curDis, int[] dis, Map<Integer, List<Integer>> graph, boolean[] visited) {
        visited[cur] = true;
        // 如果找到了更深的顶点,则更新dis数组
        if (curDis > dis[1]) {
            dis[0] = cur;
            dis[1] = curDis;
        }
        
        for (int next : graph.get(cur)) {
            if (!visited[next]) {
            	// 将递归深度传入dfs函数
                dfs(next, curDis + 1, dis, graph, visited);
            }
        }
    }
}

时空复杂度 O ( n ) O(n) O(n)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值