二叉树基础(三)

11 篇文章 0 订阅

404.左叶子之和

题意:计算给定二叉树的所有左叶子之和。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1、思路:递归法

  • 左叶子的明确定义:如果左节点不为空,且左节点没有左右孩子,那么这个节点的左节点就是左叶子
  • 递归的遍历顺序为后序遍历(左右中),是因为要通过递归函数的返回值来累加求取左叶子数值之和。
    • 确定递归函数的参数和返回值int sumOfLeftLeaves(TreeNode root),参数传入的是根节点
    • 确定终止条件,当当前节点为空,则直接返回0
    • 确定单次递归逻辑
      • 当遇到左叶子节点时,记录数值,然后通过递归求取左子树的左叶子节点和右子树的左叶子节点,相加就是整个树的左子树之和
    public int sumOfLeftLeaves(TreeNode root) {
        //DFS 递归
        if (root == null) return 0;

        int left = sumOfLeftLeaves(root.left);//左
        int right = sumOfLeftLeaves(root.right);//右

        //中
        int mid = 0;
        if (root.left != null && root.left.left == null && root.left.right == null) {
            mid += root.left.val;
        }

        int sum = left + right + mid;
        return sum;
    }

2、思路:迭代法

  • 创建一个栈实现后序遍历
  • 首先向栈中添加根节点
  • 当栈不为空时,一直循环
    • 弹出栈的头节点
    • 判断弹出的节点是否时左叶子节点,如果是的话,直接进行累加
    • 然后依次将当前节点的右节点和左节点添加到栈中
public int sumOfLeftLeaves(TreeNode root) {
    //DFS 迭代法
    if (root == null) return 0;
    Stack<TreeNode> stack = new Stack<>();
    stack.push(root);
    int sum = 0;
    while (!stack.empty()) {
        TreeNode node = stack.pop();

        if (node.left != null && node.left.left == null && node.left.right == null) {
            sum += node.left.val;
        }
        if (node.right != null) stack.push(node.right);
        if (node.left != null) stack.push(node.left);
    }
    return sum;
}

513.找树左下角的值

题意:给定一个二叉树,在树的最后一行找到最左边的值。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1、思路:迭代法

  • 只需要记录最后一行第一个节点的数值就可以了
    public int findBottomLeftValue(TreeNode root) {
        //BFS 迭代
        if (root == null) return 0;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        int result = 0;
        while (!queue.isEmpty()) {
            int size = queue.size();

            for (int i = 0; i < size; i++) {
                TreeNode node = queue.poll();

                if (i == 0) result = node.val;

                if (node.left != null) queue.offer(node.left);
                if (node.right != null) queue.offer(node.right);
            }
        }
        return result;
    }

2、思路:递归法

  • 利用递归法进行层序遍历
  • 定义一个初始深度Deep
    • 确定递归函数的参数和返回值。int findBottomLeft(TreeNode node, int deep),参数包括树的根节点和深度0
    • 确定终止条件,当当前节点等于空,就直接返回0
    • 确定单次递归的逻辑
      • 当当前节点的深度deep大于初始深度Deep,就将当前节点的深度赋值给初始深度,并将结果设置为当前节点的值
private int result;
private int Deep = 0;
public int findBottomLeftValue(TreeNode root) {
    //BFS 递归
    result = findBottomLeft(root, 0);
    return result;
}

private int findBottomLeft(TreeNode node, int deep) {
    if (node == null) return 0;
    deep++;

    if (Deep < deep) {
        Deep = deep;
        result = node.val;
    }

    findBottomLeft(node.left, deep);
    findBottomLeft(node.right, deep);
    return result;
}

112. 路径总和

题意:给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。

说明: 叶子节点是指没有子节点的节点。

image-20220601214759044

1、思路:递归法

  • 深度优先遍历法,(本题的前中后序都可以,因为对中间节点没有处理逻辑)
    • 确定递归函数和返回值,boolean hasPathSum(TreeNode root, int targetSum),参数传入树的根节点和目标值,如果要搜索其中一条符合条件的路径,那么递归一定需要返回值,因为遇到符合条件的路径了就要及时返回。
    • 确定终止条件,if (root == null) return false;如果是叶子节点,且最后值不等于0,则直接返回if (root.left == null && root.right == null) return count == 0;
    • 确定单次递归的逻辑:
      • 分别遍历树的左右子树,当遇到叶子节点时,如果叶子节点返回true,则直接返回true
    public boolean hasPathSum(TreeNode root, int targetSum) {
        //DFS 递归
        if (root == null) return false;
        //回溯
        int count = targetSum - root.val;
        //如果是叶子节点 判断是否count==0
        if (root.left == null && root.right == null) return count == 0;

        if (root.left != null) {
            boolean left = hasPathSum(root.left, count);
            if (left) return true;//找到了
        }
        if (root.right != null) {
            boolean right = hasPathSum(root.right, count);
            if (right) return true;//找到了
        }
        return false;
    }

2、思路:迭代法

  • 创建两个栈,一个栈用于后序遍历二叉树,另一个栈用于存储根节点到每个节点的和
public boolean hasPathSum(TreeNode root, int targetSum) {
    //DFS 迭代法
    if (root == null) return false;
    Stack<TreeNode> stack1 = new Stack<>();
    Stack<Integer> stack2 = new Stack<>();
    stack1.push(root);
    stack2.push(root.val);

    while (!stack1.isEmpty()) {
        TreeNode node = stack1.pop();
        int sum = stack2.pop();

        if (node.left == null && node.right == null) {
            if (sum == targetSum) return true;
        }

        if (node.left != null) {//左
            stack1.push(node.left);
            stack2.push(sum + node.left.val);
        }
        if (node.right != null) {//右
            stack1.push(node.right);
            stack2.push(sum + node.right.val);
        }
    }
    return false;
}

113. 路径总和ii

题意:给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径。

说明: 叶子节点是指没有子节点的节点。

image-20220602093856662

1、思路:递归法

  • 确定递归函数和返回值,void findPathSum(TreeNode node, int targetSum, List<Integer> paths, List<List<Integer>> result),要找到所有路径,所以递归函数不需要返回值
  • 确定终止条件,当找到叶子节点,如果Count等于0就将该路径保存到结果集中,否则直接返回
  • 确定单次递归的逻辑
    • 每次递归一开始,将当前节点值,保存到路径集合中
    • 分别遍历左右子树,每一次递归结束,则将路径集合中弹出一个;
public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
    List<List<Integer>> result = new ArrayList<>();
    if (root == null) return result;
    List<Integer> paths = new ArrayList<>();

    findPathSum(root, targetSum, paths, result);
    return result;
}

private void findPathSum(TreeNode node, int targetSum, List<Integer> paths, List<List<Integer>> result) {
    paths.add(node.val);
    int count = targetSum - node.val;
    if (node.left == null && node.right == null) {
        if (count == 0) result.add(new ArrayList<>(paths));
        else return;
    }

    if (node.left != null) {
        findPathSum(node.left, count, paths, result);
        paths.remove(paths.size() - 1);
    }

    if (node.right != null) {
        findPathSum(node.right, count, paths, result);
        paths.remove(paths.size() - 1);
    }

}

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

题意:根据一棵树的中序遍历与后序遍历构造二叉树。

注意: 你可以假设树中没有重复的元素。

image-20220602095125696

1、思路:递归法

  • 确定递归函数和返回值,TreeNode buildTree1(int[] inorder, int inLeft, int inRight, int[] postorder, int postLeft, int postRight),参数传入中序数组和后序数组,以及中序数组的左右边界和后序数组的左右边界,返回值为根节点
  • 确定终止条件
    • 如果任意数组的右边界减去左边界小于1,则直接返回null
    • 如果任意数组的右边界减去左边界等于1,则直接返回当前值的节点
  • 确定单次递归的逻辑
    • 取后序数组的最后一个元素,后序数组的最后一个即为根节点,根据后序数据的最后一个元素,在前序数组中进行查询,然后找到这个值,分界点即为这个值所在的位置。找到之后直接break
    • 然后根据这个位置进行划分左右子树
package com.yzu.lee.treenode;

/**
 * @ClassName: BuildTree
 * @Description:给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历,
 * postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。
 * @author: Leekuangyew
 * @date: 2022/5/29  14:42
 */
public class BuildTree {
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        return buildTree1(inorder, 0, inorder.length, postorder, 0, postorder.length);
    }

    private TreeNode buildTree1(int[] inorder, int inLeft, int inRight, int[] postorder, int postLeft, int postRight) {
        //没有元素了
        if (inRight - inLeft < 1) {
            return null;
        }
        //只有一个元素
        if (inRight - inLeft == 1) {
            return new TreeNode(inorder[inLeft]);
        }

        //取后序数组的最后一个元素  后序数组postorder里最后一个即为根结点
        int postVal = postorder[postRight - 1];
        TreeNode root = new TreeNode(postVal);
        int rootIndex = 0;
        for (int i = inLeft; i < inRight; i++) {
            if (inorder[i] == postVal) {
                rootIndex = i;
                break;
            }
        }

        //根据rootIndex划分左右子树
        root.left = buildTree1(inorder, inLeft, rootIndex, postorder, postLeft, postLeft + (rootIndex - inLeft));
        root.right = buildTree1(inorder, rootIndex + 1, inRight, postorder, postLeft + (rootIndex - inLeft), postRight - 1);
        return root;
    }
}

105.从前序与中序遍历序列构造二叉树

题意:根据一棵树的前序遍历与中序遍历构造二叉树。

注意: 你可以假设树中没有重复的元素。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1、思路:递归法

  • 方法与上一题类似
package com.yzu.lee.treenode;

/**
 * @ClassName: BuildTree1
 * @Description:给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。
 * @author: Leekuangyew
 * @date: 2022/5/29  15:51
 */
public class BuildTree1 {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        return buildTree1(preorder, 0, preorder.length, inorder, 0, inorder.length);
    }

    private TreeNode buildTree1(int[] preorder, int preLeft, int PreRight, int[] inorder, int inLeft, int inRight) {
        //没有元素了
        if (inRight - inLeft < 1) {
            return null;
        }
        //只有一个元素
        if (inRight - inLeft == 1) {
            return new TreeNode(inorder[inRight - 1]);
        }
        //从前序数组中取第一个元素 前序数组preorder里最后一个即为根结点
        int rootValue = preorder[preLeft];
        TreeNode root = new TreeNode(rootValue);
        int rootIndex = 0;
        for (int i = inLeft; i < inRight; i++) {
            if (inorder[i] == rootValue) {
                rootIndex = i;
                break;
            }
        }

        root.left = buildTree1(preorder, preLeft + 1, preLeft + 1 + (rootIndex - inLeft), inorder, inLeft, rootIndex);
        root.right = buildTree1(preorder, preLeft + 1 + (rootIndex - inLeft), PreRight, inorder, rootIndex + 1, inRight);
        return root;
    }
}

654.最大二叉树

给定一个不含重复元素的整数数组。一个以此数组构建的最大二叉树定义如下:

  • 二叉树的根是数组中的最大元素。
  • 左子树是通过数组中最大值左边部分构造出的最大二叉树。
  • 右子树是通过数组中最大值右边部分构造出的最大二叉树。

通过给定的数组构建最大二叉树,并且输出这个树的根节点。

image-20220602100559441

1、思路:递归法

  • 确定递归函数和返回值,TreeNode constructMaximumBinaryTree1(int[] nums, int leftIndex, int rightIndex),参数传入数组和左右边界
  • 确定终止条件,如果没有元素,则直接返回null,如果只有一个元素,则直接返回当前值的节点
  • 确定单次递归的逻辑
    • 取最大值以及最大值所在的位置,根据最大值创建节点
    • 再分别构造左右子树
package com.yzu.lee.treenode;

import javax.xml.transform.Result;

/**
 * @ClassName: ConstructMaximumBinaryTree
 * @Description:给定一个不含重复元素的整数数组。一个以此数组构建的最大二叉树定义如下: 二叉树的根是数组中的最大元素。
 * 左子树是通过数组中最大值左边部分构造出的最大二叉树。
 * 右子树是通过数组中最大值右边部分构造出的最大二叉树。
 * 通过给定的数组构建最大二叉树,并且输出这个树的根节点。
 * @author: Leekuangyew
 * @date: 2022/5/29  16:30
 */
public class ConstructMaximumBinaryTree {
    public TreeNode constructMaximumBinaryTree(int[] nums) {
        return constructMaximumBinaryTree1(nums, 0, nums.length);
    }

    private TreeNode constructMaximumBinaryTree1(int[] nums, int leftIndex, int rightIndex) {
        //没有元素了
        if (rightIndex - leftIndex < 1) {
            return null;
        }
        //只有一个元素
        if (rightIndex - leftIndex == 1) {
            return new TreeNode(nums[leftIndex]);
        }
        //取最大值
        int maxIndex = leftIndex;
        int maxValue = nums[maxIndex];
        for (int i = leftIndex + 1; i < rightIndex; i++) {
            if (nums[i] > maxValue) {
                maxIndex = i;
                maxValue = nums[i];
            }
        }
        TreeNode root = new TreeNode(maxValue);
        //构造左右子树
        root.left = constructMaximumBinaryTree1(nums, leftIndex, maxIndex);
        root.right = constructMaximumBinaryTree1(nums, maxIndex + 1, rightIndex);
        return root;
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Leekuangyee

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值