目录
题目链接:513. 找树左下角的值 - 力扣(LeetCode)
题目链接:113. 路径总和 II - 力扣(LeetCode)
题目链接:106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode)
题目链接:105. 从前序与中序遍历序列构造二叉树 - 力扣(LeetCode)
“我昨天遇到一个人,觉得她非常有意思,令我印象深刻。但今天就不再会遇到了,人生就是这样。”
题目链接:513. 找树左下角的值 - 力扣(LeetCode)
找到二叉树最底层最左边节点的值.
思路:使用广度优先搜索(BFS)遍历二叉树。BFS遍历从根节点开始,一层一层地向下遍历,在同一层中从左到右依次遍历节点。这样,当遍历到最后一层时,第一个节点即为最底层最左边的节点。
class Solution513 {
public int findBottomLeftValue(TreeNode root) {
/**
* 使用广度优先搜索(BFS)遍历二叉树.
* BFS遍历从根节点开始,一层一层地向下遍历,在同一层中从左到右依次遍历节点。
* 这样,当遍历到最后一层时,第一个节点即为最底层最左边的节点。
*/
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
TreeNode current = null;
while (!queue.isEmpty()){
current = queue.poll(); // 取出队列的第一个节点
// 先将右子节点加入队列,再将左子节点加入队列
// 这样保证最底层的最左边节点会是最后遍历到的节点
if (current.right != null) {
queue.add(current.right);
}
if (current.left != null) {
queue.add(current.left);
}
}
return current.val;
}
}
题目链接:112. 路径总和 - 力扣(LeetCode)
要判断二叉树中是否存在从根节点到叶子节点的路径,使得该路径上所有节点值的和等于给定的目标和.
思路:使用深度优先搜索(DFS)进行递归遍历。在遍历过程中,逐步累加路径上的节点值,并在到达叶子节点时检查累加值是否等于目标和。
class Solution112 {
public boolean hasPathSum(TreeNode root, int targetSum) {
if (root == null) {
return false; // 空树直接返回 false
}
return dfs(root, targetSum); // 调用递归函数
}
// 递归函数,深度优先搜索
private boolean dfs(TreeNode node, int sum) {
if (node == null) {
return false; // 到达空节点,返回 false
}
// 更新剩余的目标和
sum -= node.val;
// 如果当前节点是叶子节点,检查累加值是否等于目标和
if (node.left == null && node.right == null) {
return sum == 0;
}
// 递归检查左子树和右子树
return dfs(node.left, sum) || dfs(node.right, sum);
}
}
说明:方法dfs是递归函数,用于遍历二叉树。在遍历过程中,减去当前节点的值以更新剩余的目标和。如果当前节点是叶子节点(即左右子节点都为空),则检查当前累加值是否等于目标和。如果当前节点不是叶子节点,则递归检查其左子树和右子树。
题目链接:113. 路径总和 II - 力扣(LeetCode)
为了找出二叉树中所有从根节点到叶子节点的路径,使得这些路径的节点值之和等于给定的目标和。
思路:使用深度优先搜索(DFS)进行递归遍历。在遍历过程中,记录当前路径上的节点值,当到达叶子节点并且路径和等于目标和时,将当前路径加入结果列表。
class Solution113 {
public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
List<List<Integer>> result = new ArrayList<>();
if (root == null) {
return result; // 如果树为空,返回空列表
}
List<Integer> currentPath = new ArrayList<>();
dfs(root, targetSum, currentPath, result); // 调用递归函数
return result;
}
// 递归函数,深度优先搜索
private void dfs(TreeNode node, int sum, List<Integer> currentPath, List<List<Integer>> result) {
if (node == null) {
return; // 到达空节点,直接返回
}
// 将当前节点加入路径
currentPath.add(node.val);
sum -= node.val; // 更新剩余的目标和
// 如果当前节点是叶子节点,检查累加值是否等于目标和
if (node.left == null && node.right == null && sum == 0) {
result.add(new ArrayList<>(currentPath)); // 将当前路径加入结果集
} else {
// 递归检查左子树和右子树
dfs(node.left, sum, currentPath, result);
dfs(node.right, sum, currentPath, result);
}
// 回溯,移除当前节点
currentPath.remove(currentPath.size() - 1);
}
}
方法dfs是递归函数,用于遍历二叉树。思路如上题,在遍历过程中,将当前节点值加入路径列表,并减去当前节点值以更新剩余的目标和。如果当前节点是叶子节点且路径和等于目标和,则将当前路径加入结果集;如果当前节点不是叶子节点,则递归检查其左子树和右子树。最后,回溯,移除当前节点。
题目链接:106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode)
要从中序遍历(inorder)和后序遍历(postorder)构造二叉树,我们需要理解这些遍历序列的性质:
- 后序遍历:后序遍历的最后一个元素是二叉树的根节点。
- 中序遍历:在中序遍历中,根节点将中序遍历序列分成左子树的节点和右子树的节点。
基于上述性质,我们可以递归地构建二叉树。具体步骤如下:
- 从后序遍历的最后一个元素取出当前子树的根节点。
- 在中序遍历中找到该根节点的位置,这样可以将中序遍历分成左子树和右子树两部分。
- 根据中序遍历左子树和右子树的大小,在后序遍历中划分出对应的左子树和右子树。
- 递归地构建左右子树。
class Solution106 {
private int postIndex;
private Map<Integer, Integer> inorderIndexMap;
public TreeNode buildTree(int[] inorder, int[] postorder) {
postIndex = postorder.length - 1;
inorderIndexMap = new HashMap<>();
for (int i = 0; i < inorder.length; i++) {
inorderIndexMap.put(inorder[i], i);
}
return buildTreeHelper(inorder, postorder, 0, inorder.length - 1);
}
// 递归方法,构建二叉树
private TreeNode buildTreeHelper(int[] inorder, int[] postorder, int inorderStart, int inorderEnd) {
if (inorderStart > inorderEnd) {
return null;
}
// 从后序遍历数组中取出当前子树的根节点
int rootVal = postorder[postIndex--];
TreeNode root = new TreeNode(rootVal);
// 在中序遍历数组中找到根节点的位置
int inorderIndex = inorderIndexMap.get(rootVal);
// 递归构建右子树和左子树(注意先构建右子树,再构建左子树,因为后序遍历从后向前处理)
root.right = buildTreeHelper(inorder, postorder, inorderIndex + 1, inorderEnd);
root.left = buildTreeHelper(inorder, postorder, inorderStart, inorderIndex - 1);
return root;
}
}
题目链接:105. 从前序与中序遍历序列构造二叉树 - 力扣(LeetCode)
要从前序遍历(preorder)和中序遍历(inorder)构造二叉树,我们可以利用以下性质:
- 前序遍历:前序遍历的第一个元素是二叉树的根节点。
- 中序遍历:在中序遍历中,根节点将序列分为左子树的节点和右子树的节点。
基于这些性质,可以递归地构建二叉树。具体步骤如下:
- 从前序遍历的第一个元素取出当前子树的根节点。
- 在中序遍历中找到该根节点的位置,这样可以将中序遍历分成左子树和右子树两部分。
- 根据中序遍历左子树和右子树的大小,在前序遍历中划分出对应的左子树和右子树。
- 递归地构建左右子树。
class Solution105 {
private int preIndex = 0;
private Map<Integer, Integer> inorderIndexMap;
public TreeNode buildTree(int[] preorder, int[] inorder) {
inorderIndexMap = new HashMap<>();
for (int i = 0; i < inorder.length; i++) {
inorderIndexMap.put(inorder[i], i);
}
return buildTreeHelper(preorder, inorder, 0, inorder.length - 1);
}
// 辅助递归方法,构建二叉树
private TreeNode buildTreeHelper(int[] preorder, int[] inorder, int inorderStart, int inorderEnd) {
if (inorderStart > inorderEnd) {
return null;
}
// 从前序遍历数组中取出当前子树的根节点
int rootVal = preorder[preIndex++];
TreeNode root = new TreeNode(rootVal);
// 在中序遍历数组中找到根节点的位置
int inorderIndex = inorderIndexMap.get(rootVal);
// 递归构建左子树和右子树
root.left = buildTreeHelper(preorder, inorder, inorderStart, inorderIndex - 1);
root.right = buildTreeHelper(preorder, inorder, inorderIndex + 1, inorderEnd);
return root;
}
}
思考:为什么前序和后序不能唯一确定一棵二叉树。