训练营day18|二叉树(找树左下角值|路径总和|中序和后序构造二叉树)

513.找树左下角的值

找树最左下角的值,首先其是叶子结点。首先要是最后一行,然后是最左边的值。

 首先想到利用层序遍历每一层每一层去遍历但是通常的写法过了一遍,超出了时间限制。看题解得到“从右向左添加结点”,最后一个访问的结点就是树最左下角的值

class Solution {
    /**
     * 层序遍历找二叉树最左边的叶子结点的值---->最后一行第一个值
     *
     * @param root
     * @return
     */
    public int findBottomLeftValue(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList<>();
        if (root == null) {
            return 0;
        }
        queue.add(root);
        int ans = 0;
        while (!queue.isEmpty()) {
            TreeNode temp = queue.poll();
            if (temp.right != null) {
                queue.add(temp.right);
            }
            if (temp.left != null) {
                queue.add(temp.left);
            }
            ans = temp.val;
        }
        return ans;
    }
}

利用层序遍历,从右往左去添加结点,遍历的最后一个结点就是所求的值。

 那如果使用递归法怎么去做呢。利用前序遍历,一直去找左孩子。而哪一个是最左,指左右子树之间深度最深的那一个。深度最大的叶子结点。

在找最大深度的时候,递归的过程中依然要使用回溯

 回溯思想!

class Solution {
    /**
     * 递归去寻找最左边的值,最左叶子结点
     * 寻找最大深度处的左叶子。
     *
     * @param root
     * @return
     */
    int max_length = 0;
    int result = 0;

    public int findBottomLeftValue(TreeNode root) {
        if (root == null) {
            return 0;
        }
        travel(root, 1);
        return result;
    }

    public void travel(TreeNode root, int length) {//参数:结点+此时结点的深度
        //递归结束出口
        if (root.left == null && root.right == null) {
            if (length > max_length) {
                max_length = length;
                result = root.val;
            }
        }
        //单层递归逻辑:(注意回溯)求当前结点的深度
        if (root.left != null) {
            length++;//深度加一
            travel(root.left, length);//进行递归
            length--;//递归结束之后进行回溯
        }
        if (root.right != null) {
            length++;
            travel(root.right, length);
            length--;
        }
    }
}

112.路径总和

寻找二叉树中符合目标值的路径是否存在,point这边递归中的参数,count,是与targetSum的差值要减去当前结点的值,去判断最后是否为0.

注意回溯。

class Solution {
    /**
     * 递归寻找二叉树中符合目标值的路径,是否存在
     *
     * @param root
     * @param targetSum
     * @return
     */
    public boolean hasPathSum(TreeNode root, int targetSum) {
        if (root == null) {
            return false;
        }
        return rever(root, targetSum - root.val);
    }

    public boolean rever(TreeNode root, int count) {//count为与targetSum之间的差
        //递归结束条件
        if (root.left == null && root.right == null && count == 0) {//找到
            return true;
        }
        if (root.left == null && root.right == null) {//没找到
            return false;
        }
        //单次递归需要进行的逻辑
        if (root.left != null) {
            count -= root.left.val;
            if (rever(root.left, count)) {
                return true;
            }
            count += root.left.val;//没找着进行回溯,再把这个值加回来
        }
        if (root.right != null) {
            count -= root.right.val;
            if (rever(root.right, count)) {
                return true;
            }
            count += root.right.val;//没找着进行回溯,再把这个值加回来
        }
        return false;
    }
}

113.路径总和II

class Solution {
    /**
     * 查找二叉树有着目标和值的路径和的路径
     *
     * @param root
     * @param targetSum
     * @return
     */
    public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
        List<List<Integer>> ans = new ArrayList<>();
        if (root == null) {
            return ans;
        }
        List<Integer> paths = new ArrayList<>();
        rever(root, targetSum-root.val, paths, ans);
        return ans;
    }

    public void rever(TreeNode root, int count, List<Integer> paths, List<List<Integer>> ans) {
        paths.add(root.val);
        if (root.left == null && root.right == null && count==0 ) {
            ans.add(new ArrayList<>(paths));
        }
        if(root.left == null && root.right ==null){
            return;
        }
        if (root.left != null) {
//            count -= root.left.val;
            rever(root.left, count-root.left.val, paths, ans);
//            count += root.left.val;//回溯
            paths.remove(paths.size() - 1);
        }
        if (root.right != null) {
//            count -= root.right.val;
            rever(root.right, count- root.right.val, paths, ans);
//            count += root.right.val;//回溯
            paths.remove(paths.size() - 1);
        }
    }
}

卡了好久以为自己思路有误,因为打印出来paths的全路径出不来,只能出第一个,还以为是在递归过程中出现了什么问题(但是总体思路在上一题的基础上,计算每一次路径的和,以及回溯不仅在paths要移除那个数,并且在和的基础上药减去那个数的值)。

一直过不了是因为  ans.add(new ArrayList<>(paths))  

我一直写的是  ans.add(paths)


*106.从中序与后序遍历序列构造二叉树

以 后序数组的最后一个元素为切割点,先切中序数组,根据中序数组,反过来在切后序数组。一层一层切下去,每次后序数组最后一个元素就是节点元素。

比如中序(左中右) 9,3,15,20,7

       后序(左右中) 9,15,7,20,3

由此构造的树为  3

                        9     20

                           15     7                           

  • 第一步:如果数组大小为零的话,说明是空节点了。

  • 第二步:如果不为空,那么取后序数组最后一个元素作为节点元素。

  • 第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点

  • 第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)

  • 第五步:切割后序数组,切成后序左数组和后序右数组

  • 第六步:递归处理左区间和右区间

2022.11.24

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值