首页 > 试题广场 >

多叉树的直径

[编程题]多叉树的直径
  • 热度指数: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个注意的地方:

  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)
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)
花了5个小时写了份运行超时的代码,解题思路不对,总出现问题衍生成下一个问题,然后又去解决下一个问题,从一开始就错了。
下面这份代码运行结果是对的,但是算法量太大,本来早就应该放弃的,但是不想写道一半,明天再想想新的办法,看看能不能用权重的办法解决
/*
 * function Interval(a, b){
 *   this.start = a || 0;
 *   this.end = b || 0;
 * }
 */
function solve( n ,  Tree_edge ,  Edge_value ) {
    let nodes = [];//所有节点的数组形式
    let toZeroArr = [0];//所有节点到零节点的长度集合
    // 0节点到其他节点的长度集合
    function to_0_length(){  
        let node = nodes[0];
        let arrayVal = [];//node到其他节点的总长度集合
        let j = 1;
        while(j < nodes.length){
            let end = nodes[j];
            let length = 0;//当前节点I的总长度
            while(1){
                let index;
                for(index in Tree_edge){
                    if(end == Tree_edge[index][1]){
                        length += Edge_value[index];
                        end = Tree_edge[index][0];
                        break;
                    }
                }
                if(node == Tree_edge[index][0]){
                    break;
                }
            }
            arrayVal.push(length)
            j++;
        }
        return arrayVal;
    }
    //返回共同父亲节点下标
    function commonParentNode(node1,node2){
        let fnode1 = [node1];
        let fnode2 = [node2];
        
        for(let index=0;index<  Tree_edge.length;index++){
            let item = Tree_edge[index];
            if(node1==item[1]){
                fnode1.push(item[0])
                node1 = item[0];
                if(node1==0){
                    break
                }
                index = -1;
            }
        }
        for(let index=0;index<  Tree_edge.length;index++){
            let item = Tree_edge[index];
            if(node2==item[1]){
                fnode2.push(item[0])
                node2 = item[0];
                if(node2==0){
                    break
                }
                index = -1;
            }
        }
        fnode1 = fnode1.reverse();
        fnode2 = fnode2.reverse();
        
        let flag = 0;
        let i = 0;
        while(i<fnode1.length&&i<fnode2.length){
            if(fnode2[i]==fnode1[i]){
                flag = i;
            }
            i++;
        }
        return flag;
    }
    function toOtherNodeMaxLength(node,i){//node节点到其他节点的最大长度
        let arrayVal = [];//node到其他节点的总长度集合
        let j = i+1;
        while(j < nodes.length){
            let  k = commonParentNode(node,nodes[j]);
            arrayVal.push(toZeroArr[j]+toZeroArr[i]-2*toZeroArr[k]);
            j++;
        }
        return Math.max(...arrayVal);
    }
    
    
    Tree_edge = Tree_edge.map((item,index)=>{
        return [item.start,item.end]
    })
    //遍历所有节点 统计出各个节点
    nodes.push(Tree_edge[0][0])
    Tree_edge.map(nodeArr=>{
        nodes.push(nodeArr[1])
    })
    toZeroArr = toZeroArr.concat(to_0_length());
    let maxNodesArr = [Math.max(...toZeroArr)];
    nodes.map((item,index)=>{
        if(index!=0&&index!=nodes.length-1){
            maxNodesArr.push(toOtherNodeMaxLength(item,index));
        }
    })
    return Math.max(...maxNodesArr);
}
module.exports = {
    solve : solve
};

发表于 2021-01-17 05:45:21 回复(0)