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. 路径总和
题意:给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。
说明: 叶子节点是指没有子节点的节点。
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
题意:给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径。
说明: 叶子节点是指没有子节点的节点。
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.从中序与后序遍历序列构造二叉树
题意:根据一棵树的中序遍历与后序遍历构造二叉树。
注意: 你可以假设树中没有重复的元素。
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.最大二叉树
给定一个不含重复元素的整数数组。一个以此数组构建的最大二叉树定义如下:
- 二叉树的根是数组中的最大元素。
- 左子树是通过数组中最大值左边部分构造出的最大二叉树。
- 右子树是通过数组中最大值右边部分构造出的最大二叉树。
通过给定的数组构建最大二叉树,并且输出这个树的根节点。
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;
}
}