首页 > 试题广场 >

二叉树节点间的最大距离问题

[编程题]二叉树节点间的最大距离问题
  • 热度指数:2192 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
从二叉树的节点 A 出发,可以向上或者向下走,但沿途的节点只能经过一次,当到达节点 B 时,路径上的节点数叫作 A 到 B 的距离。
现在给出一棵二叉树,求整棵树上每对节点之间的最大距离。

输入描述:
第一行输入两个整数 n 和 root,n 表示二叉树的总节点个数,root 表示二叉树的根节点。
以下 n 行每行三个整数 fa,lch,rch,表示 fa 的左儿子为 lch,右儿子为 rch。(如果 lch 为 0 则表示 fa 没有左儿子,rch同理)
最后一行为节点 o1 和 o2。


输出描述:
输出一个整数表示答案。
示例1

输入

7 1
1 2 3
2 4 5
4 0 0
5 0 0
3 6 7
6 0 0
7 0 0

输出

5

备注:

树型DP套路。对于以某个节点为根节点的子树,有如下两种情况:
                                  
  1. 当前节点不参与路径,此时左右子树中最大路径较大的那个就是当前节点不参与路径时的最长路径。如上图红色节点(根节点)的子树中,最长路径就是两个黄色节点经过蓝色节点的路径,并未经过红色节点自身。
  2. 当前节点参与路径,此时最大的路径应该是:左树高+右树高+1(1为当前节点)。如上图中蓝色节点的子树中,最长路径就是两个黄色节点经过自己的那条路径。
这时候对于某个节点而言,只要向左右孩子节点收集信息,就能够计算它的最大路径,需要的信息有:(1) 左子树高度;(2) 右子树高度;(3) 左右孩子的最长路径。根据信息(3)我们可以求得当前节点不参与路径时的最长路径;根据信息(1)和(2)我们可以求得当前节点参与路径时的最长路径。而为了在根节点汇总整棵树的信息,每个节点需要把当前收集到的信息做一个汇总,方便自己的父节点使用:
  1. 计算以当前节点为根节点的子树高度:height=max(left_height, right_height)+1
  2. 以当前节点为根节点的子树所包含的最大路径长度:max(左子树最大路径, 右子树最大路径, 左树高+右树高+1)
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.HashMap;

class TreeNode {
    public int val;
    public TreeNode left;
    public TreeNode right;
    public TreeNode(int val) {
        this.val = val;
    }
}

// 信息体结构
class Info {
    public int maxDistance;      // 最大距离
    public int height;           // 树高
    public Info(int maxDistance, int height) {
        this.maxDistance = maxDistance;
        this.height = height;
    }
}

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String[] params = br.readLine().split(" ");
        int n = Integer.parseInt(params[0]), rootVal = Integer.parseInt(params[1]);
        // 构建树
        HashMap<Integer, TreeNode> map = new HashMap<>();
        TreeNode root = new TreeNode(rootVal);
        map.put(rootVal, root);
        for(int i = 0; i < n; i++){
            params = br.readLine().split(" ");
            int val = Integer.parseInt(params[0]);
            int leftVal = Integer.parseInt(params[1]);
            int rightVal = Integer.parseInt(params[2]);
            TreeNode node = map.get(val);
            if(leftVal != 0) {
                node.left = new TreeNode(leftVal);
                map.put(leftVal, node.left);
            }
            if(rightVal != 0) {
                node.right = new TreeNode(rightVal);
                map.put(rightVal, node.right);
            }
        }
        // 树形DP
        Info info = process(root);
        System.out.println(process(root).maxDistance);
    }
    
    private static Info process(TreeNode root) {
        if(root == null)
            return new Info(0, 0);
        Info leftInfo = process(root.left);        // 左树信息
        Info rightInfo = process(root.right);      // 右树信息
        // 经过头节点的路径
        int path1 = leftInfo.height + rightInfo.height + 1;
        // 不经过头结点的路径
        int path2 = Math.max(leftInfo.maxDistance, rightInfo.maxDistance);    // 左右子树中路径大的那个
        return new Info(Math.max(path1, path2), Math.max(leftInfo.height, rightInfo.height) + 1);
    }
}

编辑于 2021-11-18 11:07:34 回复(0)

        /**
     * 1. 最长距离不路过root,
     * 2. 最长距离路过root
     * @param root
     * @return
     */
    public static int maxDistance(TreeNode root){
        if (root == null){
            return 0 ;
        }
        //每个节点的最大距离分为上述的两种情况
        //这里需要重复的计算节点的高度
        return Math.max(height(root.left)+height(root.right)+1 ,
                Math.max(maxDistance(root.left) , maxDistance(root.right))) ;
    }

    public static int height(TreeNode root){
        if (root == null){
            return 0 ;
        }
        if (root.left == null && root.right == null){
            return 1 ;
        }
        return Math.max(height(root.left) , height(root.right))+1 ;
    }


发表于 2020-07-26 23:29:15 回复(0)
import java.util.Scanner;

public class Main{
    private static int res = 0;
    public static void main(String[] args){
        Main m = new Main();
        Scanner sc = new Scanner(System.in);
        String firstLine = sc.nextLine();
        String[] s = firstLine.split(" ");
        int n = Integer.valueOf(s[0]);
        int root = Integer.valueOf(s[1]);
        int[][] tree = new int[n][3];
        for(int i = 0;i < n;i++){
            String line = sc.nextLine();
            s = line.split(" ");
            int row = Integer.valueOf(s[0]);
            tree[row - 1][0] = Integer.valueOf(s[0]);
            tree[row - 1][1] = Integer.valueOf(s[1]);
            tree[row - 1][2] = Integer.valueOf(s[2]);
        }
        m.computeCore(tree,root);
        System.out.println(res);
    }

    private int computeCore(int[][] tree,int root){
        if(root == 0) return 0;
        int left = computeCore(tree,tree[root-1][1]);
        int right = computeCore(tree,tree[root-1][2]);
        int depth = 1 + Math.max(left,right);
                res = Math.max(res,1 + left + right);
        return depth;
    }
}  

求得每个节点的左子树深度left,右子树深度right,最大距离为所有的max(1+left+right)
编辑于 2019-12-23 15:52:40 回复(0)