代码随想录Day 18 | 找树左下角的值 路径总和 从中序与后序遍历序列构造二叉树
找树左下角的值
文档讲解:代码随想录
视频讲解:
状态
- 层序遍历:考虑题目要求最后一层最左边,那就是最后一层第一个节点,可以利用一个变量来存储每一层的第一个节点(i=0),然后层序遍历到最后一定是最后一层第一个节点
int findBottomLeftValue(TreeNode* root) {
//层序遍历获取最后一层第一个值
queue<TreeNode*> treeque;
int res;
if(root) treeque.push(root);
while(!treeque.empty())
{
int tempsize = treeque.size();
for(int i=0;i<tempsize;i++)
{
TreeNode* cur = treeque.front();
treeque.pop();
if(i==0&&cur->left==nullptr&&cur->right==nullptr)
{
res = cur->val;
}
if(cur->left) treeque.push(cur->left);
if(cur->right) treeque.push(cur->right);
}
}
return res;
}
- 递归
- 返回值和参数:返回可以没有,但每次传入的参数需要带上当前层的深度
- 终止条件:遇到每一层的第一个叶子节点就可以返回
if(root->left==nullptr && root->right == nullptr)
{
return ;
}
如果此时的层数大于记录的最大层数那么就需要更新最大层数和最左值。
if(root->left==nullptr && root->right == nullptr)
{
if(dep > maxdep)
{
maxdep = dep;
res = root->val;
}
return ;
}
- 单层递归:涉及到深度考虑使用前序遍历,必须保证先向左搜索,这样才会返回每一层最左边的值。前序遍历就涉及到要保证每一个节点的当前深度不变,而我们下一层深度是通过递归函数传递进去的,所以对左节点操作完之后,需要将深度修改回来,这就是回溯
//中节点 没有操作,如果是求深度需要记录当前节点的最大深度 maxdep = maxdep>dep ? maxdep:dep
//左节点
if(root->left)
{
//修改传入参数,及深度加1
//如果参数是引用传入int& dep
dep++;
func1(root->left,dep);
dep--;
//如果只是值传递,可以利用语言特性传入dep+1这样不会修改当前dep值
func1(root->left,dep+1);
}
具体代码
class Solution {
private:
int maxdep = INT_MIN;
int res;
public:
void GetLeft(TreeNode* root,int& dep)
{
//终止条件
if(root->left==nullptr&&root->right==nullptr)
{
if(dep > maxdep)
{
maxdep = dep;
res = root->val;
}
return;
}
//左节点
if(root->left)
{
dep++;
GetLeft(root->left,dep);
dep--;
}
//右节点
if(root->right)
{
dep++;
GetLeft(root->right,dep);
dep--;
}
return;
}
public:
int findBottomLeftValue(TreeNode* root) {
int dep = 0;
GetLeft(root,dep);
return res;
}
};
路径总和
文档讲解:代码随想录
视频讲解:
状态
昨天那道求所有路劲的方法
- 返回值和参数:返回值为bool,参数为节点,路劲上的节点构成的数组,和的计数变量
- 终止条件:当为叶子节点是返回,并计算此时的路劲和,如果是等于目标值那么返回true
- 单层递归逻辑:中节点进行压入操作,左节点和右节点递归,如果下一级函数返回的是true那么其也返回true,回溯如果path数组是使用引用传参的话。
具体代码
class Solution {
private:
int target;
public:
bool GetSum(TreeNode* root, vector<TreeNode*>& path, int sum)
{
//中节点
path.push_back(root);
//终止条件
if(root && root->left==nullptr && root->right == nullptr)
{
for(int i = 0;i<path.size();i++)
{
sum += path[i]->val;
}
if(sum == target)
{
cout << sum;
return true;
}
}
//左节点
if(root && root->left)
{
//GetSum(root->left,path,sum);
if(GetSum(root->left,path,sum)) return true;
path.pop_back();
}
//右节点
if(root && root->right)
{
//GetSum(root->right,path,sum);
if(GetSum(root->right,path,sum)) return true;
path.pop_back();
}
return false;
}
public:
bool hasPathSum(TreeNode* root, int targetSum) {
target = targetSum;
vector<TreeNode*> path;
return GetSum(root,path,0);
}
};
还可以稍微优化一下,可以将sum放进终止条件中,因为我们也只是利用它了求和
从中序与后序遍历序列构造二叉树
文档讲解:代码随想录
视频讲解: 坑很多!来看看你掉过几次坑 | LeetCode:106.从中序与后序遍历序列构造二叉树
状态
后序遍历最后一个就是根节点,前序遍历第一个就是根节点,然后根据根节点分割中序遍历,得到两个数组,
这两个数组在后序或者前序中又重复之前的步骤(相当于子树)
一定要保持切割区间的对应性,比如中序切割时是左闭右开,那么后序切割也需要是左闭右开
在后序中,由于根节点移到了最后,所以右子树从i开始
class Solution {
TreeNode* binaryTree(vector<int>& inorder, vector<int>& postorder)
{
if(postorder.size() == 0) return nullptr;
//获取树的根节点值
int rootval = postorder[postorder.size()-1];
//创建根节点作为返回值
TreeNode* root = new TreeNode(rootval);
//当前根节点在中序中的位置
int i;
for(i=0;i<inorder.size();i++)
{
if(inorder[i] == rootval) break;
}
//分割中序数组
vector<int> leftinorder(inorder.begin(),inorder.begin()+i); //[inorder[0],inorder[i-1]]
vector<int> rightinorder(inorder.begin()+i+1,inorder.end()); //[inorder[i+1],inorder[inorder.size()-1]]
//分割后序数组
//去掉最后一个数
postorder.resize(postorder.size()-1);
//leftinorder.size() = i
vector<int> leftpostorder(postorder.begin(),postorder.begin()+leftinorder.size());
vector<int> rightpostorder(postorder.begin()+leftinorder.size(),postorder.end());
//递归
root->left = binaryTree(leftinorder,leftpostorder);
root->right = binaryTree(rightinorder,rightpostorder);
return root;
}
public:
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
if (inorder.size() == 0 || postorder.size() == 0) return NULL;
return binaryTree(inorder, postorder);
}
};