程序员代码面试指南第二版 37.在二叉树中找到累加和为指定值的最长路径长度

welcome to my blog

程序员代码面试指南第二版 37.在二叉树中找到累加和为指定值的最长路径长度

题目描述
给定一颗二叉树和一个整数 sum,求累加和为 sum 的最长路径长度。路径是指从某个节点往下,每次最多选择一个孩子节点或者不选所形成的节点链。

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

输出描述:
输出一个整数表示最长链的长度。

示例1

输入
9 1
1 2 3 -3
2 4 5 3
4 0 0 1
5 8 9 0
8 0 0 1
9 0 0 6
3 6 7 -9
6 0 0 2
7 0 0 1
6

输出
4
第一次做; 哈希表前缀和方法; 该方法的通用特点:需要用到前缀和哈希表, preSum, (每个元素的位置信息); 在二叉树中使用该方法要单独注意: 如果curSum是在当前层产生的, 那么需要将curSum从sumMap中删掉, 避免出现一个分支使用了另一个分支上的前缀和的错误情况; 递归函数逻辑: 求以当前节点为结尾的所有路径上和为k的最长路径; 比左神方法中的递归函数少用了一个参数:maxLen, 这个值仅作为返回值即可, 不用作为形参
import java.util.Scanner;
import java.util.HashMap;

public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        String[] str = sc.nextLine().split(" ");
        int n = Integer.parseInt(str[0]);
        int r = Integer.parseInt(str[1]);
        TreeNode[] nodes = new TreeNode[n+1];
        for(int i=1; i<=n; i++){
            nodes[i] = new TreeNode(0);
        }
        for(int i=0; i<n; i++){
            str = sc.nextLine().split(" ");
            int index = Integer.parseInt(str[0]);
            int leftIndex = Integer.parseInt(str[1]);
            int rightIndex = Integer.parseInt(str[2]);
            int val = Integer.parseInt(str[3]);
            nodes[index].val = val;
            nodes[index].left = nodes[leftIndex];
            nodes[index].right = nodes[rightIndex];
        }
        int k = Integer.parseInt(sc.nextLine());
        //
        TreeNode root = nodes[r];
        //key是前缀和, value是前缀和最早出现的层数
        HashMap<Integer, Integer> sumMap = new HashMap<>();
        //极其重要的初始化, 这个初始化可以找出以根节点开始的路径
        sumMap.put(0,-1);
        //根节点在第0层
        int res = core(root, sumMap, 0, 0, k);
        System.out.println(res);
    }
    //max既作为返回值,又作为函数参数? 这样就不用把max设成全局变量了
    public static int core(TreeNode root, HashMap<Integer, Integer> sumMap, int preSum, int level, int k){
        //base case
        if(root==null)
            return 0;
        //
        int max = 0;
        int curSum = preSum + root.val;
        if(!sumMap.containsKey(curSum))
            sumMap.put(curSum, level);
        if(sumMap.containsKey(curSum-k)){
            //以root结尾的路径和为k的最长路径
            max = Math.max(max, level - sumMap.get(curSum-k));
        }
        //新条件新递归; 以左子树各个节点为结尾的结果; 以右子树各个节点为结尾的结果
        int leftRes = core(root.left, sumMap, curSum, level+1, k);
        int rightRes = core(root.right, sumMap, curSum, level+1, k);
        /*
        核心: 恢复现场; 
        如果curSum是在当前层加入sumMap的,curSum删掉(也就是把以当前节点结尾的前缀和删掉); 
        不删掉的话出现某一个分支使用了另一个分支上的前缀和的情况, 这样就错了;
        这是哈希表前缀和方法应用在二叉树上时要特别注意的
        */
        if(sumMap.get(curSum)==level)
            sumMap.remove(curSum);
        //最终返回三者中最大的
        return Math.max(max, Math.max(leftRes, rightRes));
    }
    public static class TreeNode{
        int val;
        TreeNode left;
        TreeNode right;
        TreeNode(int val){
            this.val = val;
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值