day17 105. 从前序与中序遍历序列构造二叉树&&106. 从中序与后序遍历序列构造二叉树&&113. 路径总和 II&&112. 路径总和&&513. 找树左下角的值
-
从前序与中序遍历序列构造二叉树(LeetCode 105)
核心思路:
使用哈希表存储中序遍历中每个值的索引,以便快速查找。
前序遍历的第一个元素是根节点。
在中序遍历中找到根节点的位置,从而确定左子树和右子树的范围。
递归构建左子树和右子树。
时间复杂度:O(n),其中 n 是树的节点数。
空间复杂度:O(n),主要来自递归调用栈和哈希表。
//105. 从前序与中序遍历序列构造二叉树
private Map<Integer, Integer> map1 = new HashMap<>();
public TreeNode buildTree1(int[] preorder, int[] inorder) {
if (preorder == null || inorder == null || preorder.length0 || inorder.length0) return null;
for (int i = 0; i < inorder.length; i++) {
map1.put(inorder[i], i);
}
return dfsBuildTree1(preorder,0,preorder.length-1,inorder,0,inorder.length-1);
}
private TreeNode dfsBuildTree1(int[] preorder,int pStart,int pEnd, int[] inorder,int inStart,int inEnd) {
if (pStart > pEnd) return null;
int val = preorder[pStart];
int idx = map1.get(val);
int leftSize=idx-inStart;//左子树中结点个数
return new TreeNode(val,
dfsBuildTree1(preorder,pStart+1,pStart+leftSize,inorder,inStart,idx-1),
dfsBuildTree1(preorder,pStart+leftSize+1,pEnd,inorder,idx+1,inEnd)
);
} -
从中序与后序遍历序列构造二叉树(LeetCode 106)
核心思路:
使用哈希表存储中序遍历中每个值的索引,以便快速查找。
后序遍历的最后一个元素是根节点。
在中序遍历中找到根节点的位置,从而确定左子树和右子树的范围。
递归构建左子树和右子树。
时间复杂度:O(n),其中 n 是树的节点数。
空间复杂度:O(n),主要来自递归调用栈和哈希表。
//106. 从中序与后序遍历序列构造二叉树
private Map<Integer, Integer> map = new HashMap<>();
public TreeNode buildTree(int[] inorder, int[] postorder) {
if (inorder == null || postorder == null || inorder.length != postorder.length) {
return null;
}
for (int i = 0; i < inorder.length; i++) {
map.put(inorder[i], i);
}
return dfsBuildTree(inorder, 0, inorder.length - 1, postorder, 0, postorder.length - 1);
}
private TreeNode dfsBuildTree(int[] inorder, int inStart, int inEnd, int[] postorder, int postStart, int postEnd) {
if (inStart > inEnd || postStart > postEnd) {
return null;
}
// 后序数组的最后一个元素是当前子树的根节点
int rootValue = postorder[postEnd];
TreeNode root = new TreeNode(rootValue);
// 在中序数组中找到根节点的位置
int rootIndex = map.get(rootValue);
// 左子树的节点数量
int leftTreeSize = rootIndex - inStart;
// 递归构建左子树
root.left = dfsBuildTree(inorder, inStart, rootIndex - 1, postorder, postStart, postStart + leftTreeSize - 1);
// 递归构建右子树
root.right = dfsBuildTree(inorder, rootIndex + 1, inEnd, postorder, postStart + leftTreeSize, postEnd - 1);
return root;
} -
路径总和 II(LeetCode 113)
问题描述:给定一棵二叉树和一个目标和,找出所有从根节点到叶子节点的路径,使得路径上的节点值之和等于目标和。
核心思路:
使用深度优先搜索(DFS)遍历树。
维护一个路径列表 path 和路径和 pathSum1。
当到达叶子节点时,检查路径和是否等于目标和,如果是,则将路径加入结果列表。
回溯时,移除当前节点并更新路径和。
时间复杂度:O(n),其中 n 是树的节点数。
空间复杂度:O(n),主要来自递归调用栈和路径列表。
//113. 路径总和 II
private int pathSum1;public List<List
> pathSum(TreeNode root, int targetSum) {
List<List> res = new ArrayList<>();
Listpath = new LinkedList<>();
if (root == null) {
return res;
}
dfsPathSum(root, res, path, targetSum);
return res;
}private void dfsPathSum(TreeNode root, List<List
> res, List path, int targetSum) {
if (root == null) return;
path.add(root.val);
pathSum1 += root.val;
if (root.left == null && root.right == null) {
if (pathSum1 == targetSum) {
res.add(new ArrayList<>(path));
}
path.remove(path.size() - 1);
pathSum1 -= root.val;
return;
}
if (root.left != null) {
dfsPathSum(root.left, res, path, targetSum);
}
if (root.right != null) {
dfsPathSum(root.right, res, path, targetSum);
}
path.remove(path.size() - 1);
pathSum1 -= root.val;
} -
路径总和(LeetCode 112)
问题描述:给定一棵二叉树和一个目标和,判断是否存在从根节点到叶子节点的路径,使得路径上的节点值之和等于目标和。
核心思路:
使用深度优先搜索(DFS)遍历树。
维护一个路径和 pathSum。
当到达叶子节点时,检查路径和是否等于目标和。
回溯时,更新路径和。
时间复杂度:O(n),其中 n 是树的节点数。
空间复杂度:O(n),主要来自递归调用栈。
//112. 路径总和
private int pathSum;public boolean hasPathSum(TreeNode root, int targetSum) {
if (root == null) return false;
return dfsHasPathSum(root, targetSum);
}private boolean dfsHasPathSum(TreeNode root, int targetSum) {
if (root == null) return false;
pathSum += root.val;
if (root.left == null && root.right == null && pathSum == targetSum) {
return true;
}
boolean flag1 = dfsHasPathSum(root.left, targetSum);
boolean flag2 = dfsHasPathSum(root.right, targetSum);
pathSum -= root.val;
return flag1 || flag2;
} -
找树左下角的值(LeetCode 513)
问题描述:给定一棵二叉树,找到树的左下角的值(即最深的左叶子节点的值)。
核心思路:
使用深度优先搜索(DFS)遍历树。
维护当前的最大高度 curHeight 和对应的值 curVal。
先遍历左子树,再遍历右子树,确保最深的左叶子节点的值被记录。
时间复杂度:O(n),其中 n 是树的节点数。
空间复杂度:O(n),主要来自递归调用栈。
//513. 找树左下角的值
private int curVal;
private int curHeight;public int findBottomLeftValue(TreeNode root) {
//层序遍历实现,效率低 4ms
/Queuequeue = new LinkedList<>(); /
queue.add(root);
List<List> list = new ArrayList<>();
while (!queue.isEmpty()) {
Listlist1 = new ArrayList<>();
int size = queue.size();
for (int i = 0; i < size; i++) {
TreeNode node = queue.poll();
list1.add(node.val);
if (node.left != null) {
queue.add(node.left);
}
if (node.right != null) {
queue.add(node.right);
}
}
list.add(list1);
}
return list.get(list.size()-1).get(0);
//递归实现,跟右视图做法一样 效率高 0ms
dfsFindBottomLeftValue(root, 0);
return curVal;
}private void dfsFindBottomLeftValue(TreeNode root, int height) {
if (root == null) {
return;
}
height += 1;
if (height > curHeight) {
curHeight = height;
curVal = root.val;
}
dfsFindBottomLeftValue(root.left, height);//先在左子树找
dfsFindBottomLeftValue(root.right, height);
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~