代码随想录算法训练营第14天|513.找树左下角的值、112.路径总和、106.从中序与后序遍历序列构造二叉树
LeetCode513
2025-02-12 16:44:54 星期三
题目描述:力扣513
文档讲解:代码随想录(programmercarl)513.找树左下角的值
视频讲解:《代码随想录》算法视频公开课 (opens new window):怎么找二叉树的左下角? 递归中又带回溯了,怎么办?| LeetCode:513.找二叉树左下角的值
代码随想录视频内容简记
这道题旗帜鲜明的一点是他没有中结点的处理过程
梳理
-
我们需要额外定义一个遍历的函数,一个参数使用根节点,另一个参数存放结点的深度。除此以外,还需要一个
result
来存放最后的最左下角的值 -
确定递归的终止条件,首先要确定是最下面一行的结点,那么就必须是叶子结点
-
确定单层递归的逻辑
大致代码内容
-
void traversal(TreeNode* root, int depth)
,一旦发现 -
在终止条件中,首先判断是不是叶子结点,之后如果有深度大于当前最大深度,那么就更新深度,
if (depth > maxDepth) maxDepth = depth
-
在单层递归中,分别对左和右进行遍历,在遍历中进行
depth++
操作,之后进入递归traversal()
,一条路径递归结束之后,开始回溯,这是最核心的一点,要进行depth--
操作
LeetCode测试
代码不算特别难写,但要注意把int result和int depth定义在函数的外部,避免定义在内部每次都要更新进行初始化
点击查看代码
class Solution {
public:
int result;
int maxDepth = INT_MIN;
void traversal(TreeNode* root, int depth) {
if (root->left == NULL && root->right == NULL) {
if (depth > maxDepth) {
maxDepth = depth;
result = root->val;
return;}
}
if (root->left) {
depth++;
traversal(root->left, depth);
depth--;
}
if (root->right) {
depth++;
traversal(root->right, depth);
depth--;
}
}
int findBottomLeftValue(TreeNode* root) {
int depth = 0;
traversal(root, depth);
return result;
}
};
LeetCode112
题目描述:力扣112
文档讲解:代码随想录(programmercarl)112.路径总和
视频讲解:《代码随想录》算法视频公开课:拿不准的遍历顺序,搞不清的回溯过程,我太难了! | LeetCode:112. 路径总和
代码随想录视频内容简记
这道题目还是不处理中结点,即采用前中后序三种皆可。另外就是这道题k哥给出的是直接传入目标值,然后在遍历中做--操作
梳理
-
定义一个新的
bool
类型的traversal()
函数,确定函数的参数有根节点root
和count
计数器 -
确定递归的终止条件,就是在是叶子结点的前提下,如果计数器的值为0,那么返回True,否则是False
-
确定单层递归的逻辑,对左和右遍历即可
大致代码内容
-
if (root->left == NULL && root->right == NULL && count == 0) return true
这是第一个终止条件,之后还要确定第二个终止条件if (root->left == NULL && root->right == NULL && count != 0) return false
-
向左遍历,如果子树的遍历结果是
true
,那么就要层层向上返回,这样来确定该条路径if (traversal(root->left, count)) return true
-
向右遍历同理
LeetCode测试
这道题注意一点就是在主函数中,调用traversal()
函数的,其count
参数应该是target - root->val
,应该把先前的root的减去。这个是卡在第61个用例上,比如[1]和1,该二叉树只有一个根节点,且要求和值为1,那么只有-1了才会符合count == 0
的要求
点击查看代码
class Solution {
public:
bool traversal(TreeNode* node, int count) {
if (node->left == NULL && node->right == NULL && count == 0) return true;
if (node->left == NULL && node->right == NULL && count != 0) return false;
if (node->left) {
count -= node->left->val;
if (traversal(node->left, count)) return true;
count += node->left->val;
}
if (node->right) {
count -= node->right->val;
if (traversal(node->right, count)) return true;
count += node->right->val;
}
return false;
}
bool hasPathSum(TreeNode* root, int targetSum) {
if (root == NULL) return false;
return traversal(root, targetSum - root->val);
}
};
LeetCode106
题目描述:力扣106
文档讲解:代码随想录(programmercarl)106.从中序与后序遍历序列构造二叉树
视频讲解:《代码随想录》算法视频公开课:坑很多!来看看你掉过几次坑 | LeetCode:106.从中序与后序遍历序列构造二叉树
代码随想录视频内容简记
梳理
-
如果数组大小为零的话,说明是空节点了。
-
如果不为空,那么取后序数组最后一个元素作为节点元素。
-
找到后序数组最后一个元素在中序数组的位置,作为切割点
-
切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)
-
切割后序数组,切成后序左数组和后序右数组
-
递归处理左区间和右区间
大致代码内容
- 首先是大致的代码框架
if (postorder.size == 0) return NULL;
int rootValue = postorder[postorder.size() - 1];
TreeNode* root = new TreeNode(rootValue);
// 叶子结点
if (postorder.size() == 1) return root;
// 找切割点
int index;
for (index = 0; index < inorder.size() - 1; index++) {
if (inorder[index] == rootValue) break;
}
// 切割中序数组
// 切割后序数组
root->left = buildTree(leftInorder,);
root->right = buildTree(中序右数组,后序右数组);
return root;
- 切割中序数组
// [0, index)
vector<int> leftInorder(inorder.begin(), inorder.begin() + index);
// [index + 1, end)
vector<int> rightInorder(inorder.begin() + index + 1, inorder.end());
- 切割后序数组
// 切割后序数组
postorder.resize(postorder.size() - 1);
vector<int> leftPastorder(postorder.begin(), postorder.begin() + leftInorder.size());
vector<int> rightPostorder(pastorder.begin() + leftInorder.size(), postorder.end());
- 递归处理左区间和右区间
root->left = traversal(中序左数组, 后序右数组);
root->right = traversal(中序右数组, 后序右数组);
return root;
LeetCode测试
这个代码有一个地方一直有问题找不出来错,找了大半天,最后找到了
int index;
for (int index = 0; index < inorder.size(); index++) {
if (inorder[index] == rootValue) break;
}
刚开始这里写的是int index
, 但是这样就会有一个问题,局部的index
,没有办法传给下面的区间做切割,相当于下面其实一直用的是index = 0
😵😵
左闭右闭
点击查看代码
class Solution {
private:
TreeNode* traversal(vector<int>& inorder, vector<int>& postorder) {
if (postorder.size() == 0) return NULL;
int rootValue = postorder[postorder.size() - 1];
TreeNode* root = new TreeNode(rootValue);
if (postorder.size() == 1) return root;
int index;
for (index = 0; index < inorder.size(); index++) {
if (inorder[index] == rootValue) break;
}
// 分割中序数组
vector<int> leftInorder(inorder.begin(), inorder.begin() + index);
vector<int> rightInorder(inorder.begin() + index + 1, inorder.end());
// 分割后序数组
postorder.resize(postorder.size() - 1);
vector<int> leftPostorder(postorder.begin(), postorder.begin() + leftInorder.size());
vector<int> rightPostorder(postorder.begin() + leftInorder.size(), postorder.end());
root->left = traversal(leftInorder, leftPostorder);
root->right = traversal(rightInorder, rightPostorder);
return root;
}
public:
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
if (inorder.size() == 0 || postorder.size() == 0) return NULL;
return traversal(inorder, postorder);
}
};
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构