首页 > 试题广场 >

多叉树的直径

[编程题]多叉树的直径
  • 热度指数:10679 时间限制: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用map记录该节点的子节点和与子节点之间的间距
    2.递归返回,该节点所能代表的最大值
    3.每次读出子节点的贡献值,进行排序,
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整型
     */
    int max = Integer.MIN_VALUE;
    public int solve (int n, Interval[] Tree_edge, int[] Edge_value) {
        // write code here
        //统计入度为0的节点,为起始节点
        boolean[] vis = new boolean[n];
        Map<Integer,ArrayList<int[]>> map = new HashMap<>();
        for(int i = 0; i < n-1;i++){
            ArrayList<int[]> curList = map.getOrDefault(Tree_edge[i].start,new ArrayList<>());
            curList.add(new int[]{Tree_edge[i].end,Edge_value[i]});
            map.put(Tree_edge[i].start,curList);
            vis[Tree_edge[i].end] = true;
        }
        int start = 0;
        for(int i = 0; i < n;i++){
            if(!vis[i]){
                start = i;
            }
        }
        int cur = process(map,start);
        return max;
    }
    
    public int process(Map<Integer,ArrayList<int[]>> map,Integer cur){
        ArrayList<int[]> curList = map.getOrDefault(cur,new ArrayList<>());
        if(curList.size() == 0){
            return 0;
        }
        int[] curArr = new int[curList.size()];
        for(int i = 0; i < curList.size();i++){
            curArr[i] = process(map,curList.get(i)[0]) + curList.get(i)[1];
        }
        Arrays.sort(curArr);
        int first = curArr[curArr.length-1];
        int second = curArr.length - 2 >= 0 ? curArr[curArr.length - 2] : 0;
        max = Math.max(max,first+second);
        return first;
    }
    
}


发表于 2022-09-04 19:11:38 回复(1)
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整型
     */

    static int[] h;
    static int[] e;
    static int[] w;
    static int[] ne;
    static int idx = 0;
    static int[] d;//以N为根节点的子树的深度;
    static int ans = 0;
    static boolean[] st;  //无向图防止子节点回到父节点
    static int cao;

    static void add(int a, int b, int c){
        e[idx] = b;
        w[idx] = c;
        ne[idx] = h[a];
        h[a] = idx++;
    }

    public int solve (int n, Interval[] Tree_edge, int[] Edge_value) {
        // write code here
        int N = n;
        int M = N*3;
        e = new int[M];
        h = new int[N];
        w = new int[M];
        ne = new int[M];
        d = new int[N];
        st = new boolean[N];
        Arrays.fill(h, -1);
        for (int i = 0; i < n-1; i++){
            add(Tree_edge[i].start, Tree_edge[i].end, Edge_value[i]);
            add(Tree_edge[i].end, Tree_edge[i].start, Edge_value[i]);
        }

        dfs(1);
        Arrays.fill(d, 0);
        Arrays.fill(st, false);
        dfs(ans);
        return d[ans];
    }

    void dfs(int u) {
        if (st[u]) return;
        st[u] = true; // 标记一下,记录为已经被搜索过了,下面进行搜索过程
        for (int i = h[u]; i != -1; i = ne[i]) {
            int j = e[i];
            if (!st[j]) { // 是否被遍历过
                d[j]=d[u]+w[i];
                if(d[j]>d[ans])ans=j;
                dfs(j);
            }
        }
    }

}
两次dfs. dfs和add均为模版代码
发表于 2022-06-19 01:48:19 回复(0)
这题用例是故意找茬是吧,给的第一个用例哪里是树啊
发表于 2021-09-03 11:38:12 回复(0)
//可参考https://www.bilibili.com/video/BV1qA411t7LR?from=search&seid=13550771883067952709,比较类似
import java.util.*;
public class Solution {
    ArrayList<ArrayList<Integer>> nei = new ArrayList<>();//邻接列表——>存储无向图的关系
    HashMap<ArrayList<Integer>, Integer> edge = new HashMap<>();//哈希表:存储边的权重
    int ans=Integer.MIN_VALUE;//最终结果
    public int solve (int n, Interval[] Tree_edge, int[] Edge_value) {
        
        //初始化邻接表
        for(int i=0;i<n;i++){
            nei.add(new ArrayList<>());
        }
        //邻接表和哈希表的写入
        for(int i=0;i<Tree_edge.length;i++){
            //无向表,所以两次写入
            int a=Tree_edge[i].start;
            int b=Tree_edge[i].end;
            //邻接列表
            nei.get(a).add(b);
            nei.get(b).add(a);
            //哈希表
            ArrayList<Integer> tmp=new ArrayList<>();
            tmp.add(a);
            tmp.add(b);
            edge.put(tmp,Edge_value[i]);
            tmp=new ArrayList<>();
            tmp.add(b);
            tmp.add(a);
            edge.put(tmp,Edge_value[i]);
        }
        boolean[] v=new boolean[n];
        dfs(0,v);
        return ans;
 }
    private int dfs(int root,boolean[] v){
        //初始化及出口条件
        v[root]=true;
        ArrayList<Integer> ls=new ArrayList<>();
        ls=nei.get(root);
        int m1=Integer.MIN_VALUE,m2=Integer.MIN_VALUE;//m1距离该节点最长的值,m2代表第2长的值
        //int m1=0,m2=0;
        //出口条件
        for(int k:ls){
            if(!v[k]){//标记为已经访问过的,则不访问
                ArrayList<Integer> e=new ArrayList<>();
                e.add(root);
                e.add(k);
                int res=Integer.MIN_VALUE;
                //递归,res代表该节点到本次的探索的长度
                res=dfs(k,v)+edge.get(e);
                //保证m1最长,m2第2长
                if(res>m1){
                    m2=m1;
                    m1=res;
                }
                else if(res>m2)
                    m2=res;
            }
        }
        //判断条件
        if(m1==Integer.MIN_VALUE){
            ans = Math.max(ans, 0);
        }
        else{
            if(m2==Integer.MIN_VALUE)
                ans = Math.max(ans, m1);
            else
                ans=Math.max(ans,m1+m2);
        }
        //从本节点出发,一直搜索到最后。将该节点设为未访问,便于从其它节点访问本节点
        v[root]=false;
        return Math.max(m1,0);//如果m1为末端或者为负,就要舍弃掉从root出发的所有路径,返回0
    }

编辑于 2021-04-10 17:23:45 回复(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)