首页 > 试题广场 >

多叉树的直径

[编程题]多叉树的直径
  • 热度指数:10685 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
给定一棵多叉树,求出这棵树的直径,即树上最远两点的距离。
包含n个结点,n-1条边的连通图称为树。
示例1的树如下图所示。其中4到5之间的路径最长,是树的直径,距离为5+2+4=11

数据范围:,保证最终结果满足
要求:空间复杂度:,时间复杂度
示例1

输入

6,[[0,1],[1,5],[1,2],[2,3],[2,4]],[3,4,2,1,5]

输出

11
示例2

输入

2,[[0,1],[1,2]],[1]

输出

1
思路:
1. 先从初始点出发,一直探索到最底层,也就是离初始点最远的一个端点。这个端点必定是我们最后所求的最长距离的其中一个端点(证明过程百度噢)。
2. 找到这个端点,然后从这个端点出发,探索距离此点最远的点。

技巧:
1. graph的构建采用了 List<List<Integer>>的结构,第一层的List的索引,为当前端点的值。
2. 用了一个HashMap<Integer, HashMap<Integer, Integer>>来存放每条边的权重。

代码: 
import java.util.*;

/*
 * public class Interval {
 *   int start;
 *   int end;
 * }
 */

public class Solution {
    /**
     * 树的直径
     * @param n int整型 树的节点个数
     * @param Tree_edge Interval类一维数组 树的边
     * @param Edge_value int整型一维数组 边的权值
     * @return int整型
     */
    List<List<Integer>> graph = new ArrayList<>();    //用来存图结构
    Map<Integer, Map<Integer,Integer>> table =new  HashMap<>(); //用来存图权重
    
    int maxEdges=0;
    int maxIndex=-1;
    
    public int solve (int n, Interval[] Tree_edge, int[] Edge_value) {
        // write code here
        for(int i=0; i<n; i++){
            graph.add( new ArrayList<Integer>());
        }
        
        //构建graph,和table用于查询各边的权重
        for(int i=0; i<Tree_edge.length;i++){
            Interval edge=Tree_edge[i];
            graph.get(edge.start).add(edge.end); //建立图
            graph.get(edge.end).add(edge.start); //因为是无向图,所以也得反向连接一下
            
            //构建表
            if(!table.containsKey(edge.start)) table.put(edge.start, new HashMap<Integer, Integer>());
            table.get(edge.start).put(edge.end,Edge_value[i]);
            if(!table.containsKey(edge.end)) table.put(edge.end, new HashMap<Integer, Integer>()); 
            table.get(edge.end).put(edge.start,Edge_value[i]);
            
         }
        
        dfs(0,0,-1);
        dfs(0,maxIndex,-1);
        
        return maxEdges;

    }
    
    public void dfs(int count, int node, int parent){
        List<Integer> cur = graph.get(node);
        
        for(int i=0; i<cur.size(); i++){     //可行性剪枝?反正就是不允许dfs往回走到父节点
            if(cur.get(i)==parent){
                continue; 
            }
            int value=table.get(node).get(cur.get(i));
            dfs(count+value, cur.get(i),node);
        }
        
        if(count>maxEdges){
            maxEdges=count;
            maxIndex=node;
        }
    }
}
最后,这题叫简单吗?可QNMLGB吧。这题是二叉树问题吗(虽然之前也用二叉树写了一下,确实可以写)。。。这题明明就是无向图。。。

发表于 2021-01-20 18:04:49 回复(0)
 
从任一点出发,找到该点到达最远的点p
从点p出发找到p点到达最远的点 q
p q之间的距离即为树中最远的两个点  int point_p;
    int point_q;
    bool visit[100000];
    int Max=-1;
    int max_len=-1;
    bool first_dfs=true;//第几次调用dfs
    int solve(int n, vector<Interval>& Tree_edge, vector<int>& Edge_value) {
        // write code here
        for(int i=0;i<n;i++)
            visit[i]=false;  //初始化
        dfs(Tree_edge[0].start,0,Tree_edge,Edge_value);//从任意一个点开始  找到该点所能到达的最远的点point_p
        for(int i=0;i<n;i++)
            visit[i]=false;  //初始化
        Max=-1;
        first_dfs=false;
        dfs(point_p,0,Tree_edge,Edge_value);//从point_p 找到该点所能到达的最远的点 point_q
        
        //那么point_p  到 point_q之间的距离即为  树的直径
        for(int i=0;i<n;i++)
            visit[i]=false;  //初始化
        len(point_p,point_q,0,Tree_edge,Edge_value);//获得长度
        
        return max_len;
        
        
        
        
        
        
        
    }
    
    bool len(int point1,int point2,int length,vector<Interval>& Tree_edge, vector<int>& Edge_value)
    {
        visit[point1]=true;
        if(point2==point1) //已经访问到该点
        {
            max_len=length;
            return true;
        }
         for(int i=0;i<Tree_edge.size();i++)
        {
            
            //dfs 进入未访问的节点
            if(Tree_edge[i].start==point1 && visit[Tree_edge[i].end]==false)
            {
                if(len(Tree_edge[i].end,point2,length+Edge_value[i],Tree_edge,Edge_value))
                    return true;
            }
            
            if(Tree_edge[i].end==point1 && visit[Tree_edge[i].start]==false)
            {
               if(len(Tree_edge[i].start,point2,length+Edge_value[i],Tree_edge,Edge_value))
                   return true;
            }
        }
        visit[point1]=false;

        
        return false;
    }
    
    
    
    void dfs(int point,int length, vector<Interval>& Tree_edge, vector<int>& Edge_value)
    {
        
        if(length>Max)    //每访问一个点
        {
            Max=length;
            if(first_dfs)
               point_p=point;
            else
                point_q=point;
        }
        visit[point]=true;//标记为已经访问
        for(int i=0;i<Tree_edge.size();i++)
        {
            
            //dfs 进入未访问的节点
            if(Tree_edge[i].start==point && visit[Tree_edge[i].end]==false)
                dfs(Tree_edge[i].end,length+Edge_value[i],Tree_edge,Edge_value);
            
            if(Tree_edge[i].end==point && visit[Tree_edge[i].start]==false)
                dfs(Tree_edge[i].start,length+Edge_value[i],Tree_edge,Edge_value);
        }
        visit[point]=false;

    }
    

发表于 2020-09-06 12:39:18 回复(1)

本题需要1个注意的地方:

  1. 这是无向树(没有环的无向图),没有子节点、父节点之分,所以题目给的Tree_edge记录的边的start和end并不一定对应:比如0 -> 1 -> 2 图,可以描述为:[[0, 1], [2, 1]];所以需要重新用邻接表对图进行描述,然后利用dfs进行遍历。(图的路径就是一个节点最大两边的和,树是子树最大的两个路径的和, 树有层次)
    function solve( n ,  Tree_edge ,  Edge_value ) {
     let res = 0;
     const obj= {};
     for (let i=0; i<Tree_edge.length; ++i) {
         const v = Tree_edge[i];
         const w = Edge_value[i] || 0;
         obj[v.start] ? obj[v.start].push([w, v.end]):
                     obj[v.start] = [[w, v.end]];
         obj[v.end] ? obj[v.end].push([w, v.start]):
                     obj[v.end] = [[w, v.start]];
     }
     const dfs = (node, pre, w) => {
         let i=0;
         const arr = [];
         while(i<obj[node].length) {
             if (obj[node][i][1] !== pre) 
                 arr.push(dfs(obj[node][i][1], node, obj[node][i][0]));
             ++i;
         }
         arr.push(0, 0); // 防止没有
         const one = Math.max(...arr);
         arr[arr.indexOf(one)] = -Infinity;
         const two = Math.max(...arr);
         if (one + two > res) res = one + two;
         return one + w;
     };
     dfs(Tree_edge[0].start, -1, Edge_value[0]);
     return res;
    }
发表于 2021-12-25 15:44:35 回复(0)
/**
 * struct Interval {
 *	int start;
 *	int end;
 * };
 */

class Solution {
public:
  /**
   * 树的直径
   * @param n int整型 树的节点个数
   * @param Tree_edge Interval类vector 树的边
   * @param Edge_value int整型vector 边的权值
   * @return int整型
   */
  int solve(int n, vector<Interval>& Tree_edge, vector<int>& Edge_value) {
    // build the tree
    vector<vector<pair<int, long>>> tree(n);
    for (int i = 0; i < Tree_edge.size(); ++i) { // key: 无向图要建双向边
      const auto e = Tree_edge[i];
      tree[e.start].emplace_back(e.end, Edge_value[i]);
      tree[e.end].emplace_back(e.start, Edge_value[i]);
    }

    int ans = 0;
    function<int(int, int, int)> dfs = [&](int cur, int parent, int weight) {
      int first = 0, second = 0;
      for (const auto& nei : tree[cur]) {
        if (nei.first == parent) continue;
        int len = dfs(nei.first, cur, nei.second);
        if (len > first) second = first, first = len; // 超过第一长的边,原先第一长的边就变第二长
        else if (len > second) second = len;          // 超过第二长的边,原先第一长的边还是第一长
      }
      ans = max(ans, first + second);
      return weight + first;
    };
    
    dfs(0, -1, 0);
    return ans;
  }
};

发表于 2021-07-06 16:09:04 回复(0)
function solve( n ,  Tree_edge ,  Edge_value ) {
    const tree = buildTree(n, Tree_edge, Edge_value);
    const visited = new Array(n).fill(false);
    const {max} = dfs({tree, visited});
    return max;
}
function buildTree(n, tree_edge, edge_value) {
    const tree = new Array(n).fill(null).map(_ => []);
    for (let i = 0; i < tree_edge.length; i++) {
        const {start, end} = tree_edge[i];
        const edge_val = edge_value[i];
        tree[start].push({child: end, len: edge_val});
        tree[end].push({child: start, len: edge_val});
    }
    return tree; 
}

function dfs({tree, visited, idx = 0, max = 0}) {
    if (tree[idx].length === 0 || visited[idx]) return 0;
    visited[idx] = true;
    let m1 = 0, m2 = 0;
    for (let i = 0; i < tree[idx].length; i++) {
        const {child, len} = tree[idx][i];
        if (visited[child]) continue;
        const res = dfs({tree, visited, idx: child, max: max});
        const distance = res.maxDistance + len;
        max = res.max;
        if (distance >= m1) {
            m2 = m1;
            m1 = distance;
        } else if (distance > m2) {
            m2 = distance;
        }
    }
    max = Math.max(max, m1 + m2);
    return {maxDistance: m1, max: max};
}

编辑于 2021-04-18 12:20:19 回复(0)
该题为求多叉树的直径、第二直径的问题。
前几天在牛客巅峰赛上遇到了,赛后主讲人讲了一个通用的思路。对于此类问题,我们需要构建图来做深度优先搜索。
1. 首先,根据父子关系及边权重构建无向图;
2. 然后,随机找一顶点,利用深度优先搜索找到距离该点最远的顶点remote。
3. 最后,从remote顶点开始深度优先搜索找到最长路径,该路径即为直径。
public class Solution {
    /**
     * 树的直径
     * @param n int整型 树的节点个数
     * @param Tree_edge Interval类一维数组 树的边
     * @param Edge_value int整型一维数组 边的权值
     * @return int整型
     */
    public int solve (int n, Interval[] Tree_edge, int[] Edge_value) {
        // write code here
        if(Tree_edge == null || Edge_value == null || Tree_edge.length != Edge_value.length){return 0;}
        Map<Integer, List<Edge>> graph = new HashMap<>();
        int len = Tree_edge.length;
        for(int i = 0; i < len; ++i){
            Interval inter = Tree_edge[i];
            int start = inter.start;
            int end = inter.end;
            int w = Edge_value[i];
            Edge e1 = new Edge(end, w);
            if(!graph.containsKey(start)){
                List<Edge> temp = new ArrayList<>();
                graph.put(start, temp);
            }
            graph.get(start).add(e1);
            Edge e2 = new Edge(start, w);
            if(!graph.containsKey(end)){
                List<Edge> temp = new ArrayList<>();
                graph.put(end, temp);
            }
            graph.get(end).add(e2);
        }
        int[] remote = {0, 0};    // remote[0] 代表以0为起点的最长路径长度, remote[1]代表最长路径的终点
        dfs(graph, 0, -1, 0, remote);
        int[] res = {0, 0};
        dfs(graph, remote[1], -1, 0, res);
        return res[0];
    }
    
    private class Edge{
        int end;
        int w;
        Edge(int end, int w){
            this.end = end;
            this.w = w;
        }
    }
    
    private void dfs(Map<Integer, List<Edge>> graph, int from, int prev, int path, int[] res){
        List<Edge> edges = graph.get(from);
        for(Edge edge: edges){
            if(edge.end != prev){
                path += edge.w;
                if(path > res[0]){
                    res[0] = path;
                    res[1] = edge.end;
                }
                dfs(graph, edge.end, from, path, res);
                path -= edge.w;    // 回溯
            }
        }
    }
}




编辑于 2020-12-03 21:08:35 回复(5)
首先,这一道题不难,就是一个树的后序遍历,但是这个题目麻烦的地方在于给的数据有没描述清楚的地方。
题目给的是一个树,而不是一个二叉树。其次,题目也不是按照边的次序给的数据,有的数据是从子节点指向父节点。所以,处理的时候要注意一点。
最后说一说我的思路:后序遍历一棵树,遍历的时候,更新树的最大直径,树的最大直径肯定是某个子树或根上两个孩子最大深度之和,如果只有一个孩子,另一个节点就是父节点。
int postOrder(unordered_map<int, vector<pair<int,int>>> &tree, int node, int &res,int parent){
    vector<int> children;
    for(auto child : tree[node]){
        if(child.first != parent){
            int len = postOrder(tree,child.first,res,node);
            children.push_back(child.second + len);
        }
    }
    if(children.size() == 0){
        return 0;
    }
    sort(children.begin(),children.end(),greater<int>());
    int len = children[0];
    int maxLen = len;
    if(children.size() > 1){
        maxLen += children[1];
    }
    res = max(maxLen,res);
    return len;
}

int solve(int n, vector<Interval>& Tree_edge, vector<int>& Edge_value) {
    if(Tree_edge.size() == 0){
        return 0;
    }
    unordered_map<int, vector<pair<int,int>>> tree;
    for(int i=0;i<Tree_edge.size();i++){
        Interval edge = Tree_edge[i];
        int value = Edge_value[i];
        if(tree.find(edge.start) == tree.end()){
            tree[edge.start] = vector<pair<int,int>>();
        }
        if(tree.find(edge.end) == tree.end()){
            tree[edge.end] = vector<pair<int,int>>();
        }
        tree[edge.start].push_back(make_pair(edge.end,value));
        tree[edge.end].push_back(make_pair(edge.start,value));
    }
    int res = 0;
    int root = Tree_edge[0].start;
    postOrder(tree,root,res,root);
    return res;
}


发表于 2020-11-14 16:01:42 回复(0)
这个题竟然是简单?
发表于 2020-10-08 20:58:21 回复(2)

DFS

参考leetcode上的1245. Tree Diameter

可以把树看作是一个没有环的无向图,使用深度优先搜素的思想遍历整棵树。由于没有环,所有不需要visit数组记录访问过的节点,只需要每次传入父节点保证子节点不会返回访问父节点。

class Edge {
    int neighbor;
    int weight;
    Edge(int neighbor, int weight) {
        this.neighbor = neighbor;
        this.weight = weight;
    }
}
public class Solution {
    private int diameter = 0;
    public int solve (int n, Interval[] Tree_edge, int[] Edge_value) {
        // 使用数组保存所有的节点
        List<Edge>[] graph = new List[n];
        for (int i = 0; i < n; i++) {
            graph[i] = new ArrayList<>();
        }
        for (int i = 0; i < Tree_edge.length; i++) {
            Interval interval = Tree_edge[i];
            int value = Edge_value[i];
            // 由于是无向图,所有每条边都是双向的
            graph[interval.start].add(new Edge(interval.end, value));
            graph[interval.end].add(new Edge(interval.start, value));
        }
        // 随机从一个节点开始dfs,这里选择的是0
        dfs(graph, 0, -1);
        return diameter;
    }
    // dfs返回值为从node节点开始的最长深度
    private int dfs(List[] graph, int node, int parent) {
        int maxDepth = 0; //从节点开始的最长深度
        int secondMaxDepth = 0; //从节点开始的第二长深度
        for (Edge edge : graph[node]) {
            int neighbor = edge.neighbor;
            if (neighbor == parent) continue; // 防止返回访问父节点
            int depth = edge.weight + dfs(graph, neighbor, node);
            if (depth > maxDepth) {
                secondMaxDepth = maxDepth;
                maxDepth = depth;
            }else if (depth > secondMaxDepth) {
                secondMaxDepth = depth;
            }
        }
        // maxDepth + secondMaxDepth为以此节点为中心的直径
        diameter = Math.max(diameter, maxDepth + secondMaxDepth);
        return maxDepth;
    }
}
编辑于 2021-03-01 04:49:53 回复(1)
别被题骗了,根本不是树,是一个无向图,通过贪婪求出最长路径。
编辑于 2021-01-01 12:43:40 回复(0)
题目tm看不懂
发表于 2020-11-24 09:39:17 回复(0)
牛客网真的是垃圾的一匹,自己写了个python代码超时,把已通过的代码里的原样复制粘贴一样超时。你们这样会耽误别人前程的,能不能干点人事?
发表于 2021-03-31 21:18:10 回复(0)
# class Interval:
#     def __init__(self, a=0, b=0):
#         self.start = a
#         self.end = b

#
# 树的直径
# @param n int整型 树的节点个数
# @param Tree_edge Interval类一维数组 树的边
# @param Edge_value int整型一维数组 边的权值
# @return int整型
#
from collections import defaultdict        
class Solution:
    def solve(self , n , Tree_edge , Edge_value ):
        # write code here
        graph, table = {}, defaultdict()
        for i in range(len(Tree_edge)):
            graph.setdefault(Tree_edge[i].start, []).append(Tree_edge[i].end), graph.setdefault(Tree_edge[i].end, []).append(Tree_edge[i].start)
            table[(Tree_edge[i].start, Tree_edge[i].end)], table[(Tree_edge[i].end, Tree_edge[i].start)] = Edge_value[i], Edge_value[i]
        self.res, self.maxIndex =  0, -1
        def dfs(cnt, node, parent):
            cur = graph[node]
            for i in range(len(cur)):
                if cur[i] == parent:
                    continue
                dfs(cnt+table[(node,cur[i])], cur[i], node)
            if cnt > self.res:
                self.res = cnt
                self.maxIndex = node
        
        dfs(0, 0, -1)
        dfs(0, self.maxIndex, -1)
        return self.res
    

发表于 2021-06-16 16:06:02 回复(0)
#include <vector>
#include <unordered_map>
#include <list>
#include <algorithm>
using namespace std;

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 树的直径
     * @param n int整型 树的节点个数
     * @param Tree_edge Interval类vector 树的边
     * @param Edge_value int整型vector 边的权值
     * @return int整型
     */
    int solve(int n, vector<Interval>& Tree_edge, vector<int>& Edge_value) {
        // 如果边或权值数组为空,或者长度不匹配,返回0
        if (Tree_edge.empty() || Edge_value.empty() || Tree_edge.size() != Edge_value.size()) return 0;

        // 构建图的邻接表
        unordered_map<int, list<Edge>> graph;
        int len = Tree_edge.size();
        for (int i = 0; i < len; ++i) {
            int start = Tree_edge[i].start;
            int end = Tree_edge[i].end;
            int w = Edge_value[i];
            
            // 添加边 start -> end
            graph[start].emplace_back(end, w);
            // 添加边 end -> start (无向图)
            graph[end].emplace_back(start, w);
        }
        
        // 记录以节点0为起点的最长路径长度和终点
        pair<int, int> remote = {0, 0}; 
        dfs(graph, 0, -1, 0, remote);
        
        // 以远端节点为新的起点再次进行DFS,计算最长路径
        pair<int, int> result = {0, 0};
        dfs(graph, remote.second, -1, 0, result);
        
        return result.first; // 返回最长路径长度
    }

private:
    // 边的结构体,包含终点和权重
    struct Edge {
        int end;
        int weight;
        Edge(int e, int w) : end(e), weight(w) {}
    };
    
    // 深度优先搜索,用于找到最长路径
    void dfs(unordered_map<int, list<Edge>>& graph, int from, int prev, int path, pair<int, int>& res) {
        // 遍历当前节点的所有相邻边
        for (const auto& edge : graph[from]) {
            if (edge.end != prev) { // 跳过回到父节点的边
                path += edge.weight;
                
                // 更新最长路径信息
                if (path > res.first) {
                    res.first = path;
                    res.second = edge.end;
                }
                
                // 继续递归DFS
                dfs(graph, edge.end, from, path, res);
                path -= edge.weight; // 回溯,恢复路径长度
            }
        }
    }
};

发表于 2024-11-10 14:42:49 回复(0)
经典题目树的直径
class Solution:
    def solve(self , n: int, Tree_edge: List[Interval], Edge_value: List[int]) -> int:
        g = [[] for _ in range(n)]
        for i, w in zip(Tree_edge, Edge_value):
            g[i.start].append([i.end, w])
            g[i.end].append([i.start, w])
        res = 0
        def dfs(root: int, fa: int) -> int:
            p = 0
            for e, w in g[root]:
                if e == fa:
                    continue
                c = dfs(e, root) + w
                nonlocal res
                res = max(res, c + p)
                p = max(p, c)
            return p
        
        dfs(0, -1)
        return res

发表于 2024-08-09 20:11:37 回复(0)
这道题 GPT-4 一次性做出来,Claud3-opus 无法顺利完成,如下是 GPT4的解答:

好的,我们来详细讨论如何使用 Java 实现树的直径的计算。问题可以通过使用两次广度优先搜索(BFS)的方法来高效解决:

1. **第一次广度优先搜索(BFS)**:从任意一个节点开始,使用 BFS 找到距离它最远的节点。我们称这个节点为 A。
2. **第二次广度优先搜索(BFS)**:从节点 A 开始,再次使用 BFS 找到距离 A 最远的节点。这个距离即为树的直径。

这种方法之所以有效,是因为从树中任何一个节点到达的最远节点都是直径的一端。

现在来看如何在 Java 中实现这个算法。首先,我们需要根据输入的边构建树的邻接表,然后实现 BFS。这里是具体的实现步骤:

import java.util.*;

public class Solution {
    public int solve(int n, Interval[] Tree_edge, int[] Edge_value) {
        // 创建邻接表,记录节点及对应边的权重
        Map<Integer, List<int[]>> graph = new HashMap<>();
        for (int i = 0; i < Tree_edge.length; i++) {
            Interval edge = Tree_edge[i];
            int start = edge.start;
            int end = edge.end;
            int weight = Edge_value[i];

            graph.computeIfAbsent(start, k -> new ArrayList<>()).add(new int[]{end, weight});
            graph.computeIfAbsent(end, k -> new ArrayList<>()).add(new int[]{start, weight});
        }

        // 第一次 BFS,找到任意起点到最远点 A
        int[] farthest = bfs(graph, 0);
        // 第二次 BFS,从 A 出发找到最远距离
        int[] result = bfs(graph, farthest[0]);

        return result[1]; // result[1] 存储的是最大距离
    }

    // 辅助方法,进行 BFS 并返回最远点及其距离
    private int[] bfs(Map<Integer, List<int[]>> graph, int start) {
        Queue<int[]> queue = new LinkedList<>();
        Map<Integer, Boolean> visited = new HashMap<>();

        queue.offer(new int[]{start, 0}); // 数组内部:[当前节点, 当前距离]
        visited.put(start, true);

        int farthestNode = start;
        int maxDistance = 0;

        while (!queue.isEmpty()) {
            int[] current = queue.poll();
            int currentNode = current[0];
            int currentDistance = current[1];

            if (currentDistance > maxDistance) {
                maxDistance = currentDistance;
                farthestNode = currentNode;
            }

            // 遍历当前节点的所有邻接节点
            if (graph.containsKey(currentNode)) {
                for (int[] neighbor : graph.get(currentNode)) {
                    if (!visited.getOrDefault(neighbor[0], false)) {
                        visited.put(neighbor[0], true);
                        queue.offer(new int[]{neighbor[0], currentDistance + neighbor[1]});
                    }
                }
            }
        }

        return new int[]{farthestNode, maxDistance};
    }
}

// 辅助类,用于表示边的起点和终点
class Interval {
    int start;
    int end;

    public Interval(int start, int end) {
        this.start = start;
        this.end = end;
    }
}



这段代码首先构建了一个图的邻接表,然后通过两次 BFS 来找到树的直径。一次 BFS 找到任意起点到最远点 A 的距离,然后从 A 出发再做一次 BFS 来确定最大距离。

发表于 2024-05-06 16:54:53 回复(0)
bfs一遍通过
```c++
    int solve(int n, vector<Interval>& Tree_edge, vector<int>& Edge_value) {
        // write code here
        int cnt=0;
        vector<vector<pair<int,int>>> edge(n);
        for(int i=0;i<n-1;i++){//建立邻接表
            edge[Tree_edge[i].start].emplace_back(make_pair(Tree_edge[i].end,Edge_value[i]));
            edge[Tree_edge[i].end].emplace_back(make_pair(Tree_edge[i].start,Edge_value[i]));
        }
        auto bfs=[&](int start){
            queue<int> q;
            vector<int> state(n);
            vector<int> dis(n);
            q.push(start);
            state[start]=1;
            while(!q.empty()){
                int t=q.front();
                q.pop();
                for(auto p:edge[t]){
                    if(state[p.first]==0){//未访问过则入队
                        q.push(p.first);
                        dis[p.first]=dis[t]+p.second;
                        state[p.first]=1;
                    }
                }
            }
            auto m=max_element(dis.begin(),dis.end());
            int index=m-dis.begin();
            return make_pair(index,*m);
        };
        auto t=bfs(0);
        auto t1=bfs(t.first);
        return t1.second;
    }

编辑于 2024-03-07 10:57:51 回复(0)
临界矩阵超空间复杂度了,得用临界矩阵
import java.util.*;

/*
 * public class Interval {
 *   int start;
 *   int end;
 *   public Interval(int start, int end) {
 *     this.start = start;
 *     this.end = end;
 *   }
 * }
 */

public class Solution {
    class Edge {
        int to;
        int weight;
        public Edge(int to, int weight) {
            this.to = to;
            this.weight = weight;
        }
    }
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 树的直径
     * @param n int整型 树的节点个数
     * @param Tree_edge Interval类一维数组 树的边
     * @param Edge_value int整型一维数组 边的权值
     * @return int整型
     */
    int max = Integer.MIN_VALUE;
    boolean visited[][];
    public int solve (int n, Interval[] Tree_edge, int[] Edge_value) {
        // write code here
        // 转临接表
        HashMap<Integer, ArrayList<Edge>> map = new HashMap<>();
        
        visited = new boolean[n][n];
        for(int i = 0; i < Tree_edge.length; i++) {
            Interval edge = Tree_edge[i];
            map.putIfAbsent(edge.start, new ArrayList<>());
            map.putIfAbsent(edge.end, new ArrayList<>());
            map.get(edge.start).add(new Edge(edge.end, Edge_value[i]));
            map.get(edge.end).add(new Edge(edge.start, Edge_value[i]));
        } 
        dfs(0, map);
        return max;
    }

    public int dfs(int curIndex, HashMap<Integer, ArrayList<Edge>> map) {
        int s1 = 0;
        int s2 = 0;
        List<Edge> sonList = map.get(curIndex);
        for(int i = 0; i <sonList.size(); i++) {
            int to = sonList.get(i).to;
            int weight = sonList.get(i).weight;

            if(visited[curIndex][to]) continue;
            visited[curIndex][to] = true;
            visited[to][curIndex] = true;
            int son = dfs(to, map) + weight;
            if(son > s1) {
                s2 = s1;
                s1 = son; 
            } else if(s2 < son && s1 > son) s2 = son;
        }
        max = Math.max(max, Math.max(s1, s1 + s2));
        return s1;
    }
}

编辑于 2024-01-24 11:06:38 回复(0)
import sys

class Solution(object):
    def solve(self, n, edges, weight):
        g = [{} for _ in range(n)]
        for i, z in enumerate(edges):
            x = z.start
            y = z.end
            g[x][y] = weight[i]
            g[y][x] = weight[i]
        d1 = [0] * n  # s出发的最长
        d2 = [0] * n  # s出发的次长
        self.d = 0
        vst = {}

        def dfs(s):
            vst[s] = 1
            for k, v in g[s].items():
                if vst.get(k, 0):
                    continue
                dfs(k)
                t = d1[k] + v  # k出发的最长路+此时边的权值
                if t > d1[s]:
                    d2[s] = d1[s]
                    d1[s] = t
                elif t > d2[s]:
                    d2[s] = t
            self.d = max(self.d, d1[s] + d2[s])

        dfs(0)
        return self.d


发表于 2023-03-14 16:06:02 回复(0)
广度优先搜索两次找出最远的点和最远距离
/**
 * struct Interval {
 *  int start;
 *  int end;
 * };
 */

class Solution {
  public:
    /**
     * 树的直径
     * @param n int整型 树的节点个数
     * @param Tree_edge Interval类vector 树的边
     * @param Edge_value int整型vector 边的权值
     * @return int整型
     */
    vector<vector<pair<int, pair<int, bool>>>> graph;//注:这里的空间复杂度实际是O(2n)
    int solve(int n, vector<Interval>& Tree_edge, vector<int>& Edge_value) {
        graph.resize(n);
        for (int i = 0; i < n - 1; i++) {
            graph[Tree_edge[i].start].push_back(pair<int, pair<int, bool>>(Tree_edge[i].end, pair<int, bool>(Edge_value[i], false)));
            graph[Tree_edge[i].end].push_back(pair<int, pair<int, bool>>(Tree_edge[i].start, pair<int, bool>(Edge_value[i], false)));
        }
        return bfs(bfs(0, 0).first, 0).second;
    }
    pair<int, int> bfs(int i, int len) {/*i是接下来走哪里, len是已经走了多远*/
        pair<int, int> farmost(i, len); //<最远走到了哪里, 最远走了多远>
        for (auto& it : graph[i]) {
            if (it.second.second) continue;
            it.second.second = true;
            auto jt = graph[it.first].begin();
            for (; jt != graph[it.first].end(); jt++) if (jt->first == i) {
                    jt->second.second = true;
                    break;
                }
            pair<int, int> temp = bfs(it.first, len + it.second.first);
            if (temp.second > farmost.second)farmost = temp;
            it.second.second = false;
            jt->second.second = false;
        }
        return farmost;
    }
};


发表于 2023-03-08 15:52:00 回复(0)