这道题目我看到后的第一思路是:层序遍历,每层的第一个都有可能是所需要返回的值,依据层序遍历的模板写代码即可:
class Solution {
public:
int findBottomLeftValue(TreeNode* root) {
int res;
queue<TreeNode*> q;
if(root==nullptr) return INT_MAX;
q.push(root);
while(!q.empty())
{
int len=q.size();
res = q.front()->val;
for(int i=0;i<len;i++)
{
TreeNode* node=q.front();
q.pop();
if(node->left) q.push(node->left);
if(node->right) q.push(node->right);
}
}
return res;
}
};
当然这道题目也可以用递归法,带有回溯思想,递归三部曲:
1. 确定递归函数的参数和返回值
参数必须有要遍历的树的根节点,还有就是一个int型的变量用来记录最长深度。 这里就不需要返回值了,所以递归函数的返回类型为void。本题还需要类里的两个全局变量,maxLen用来记录最大深度,result记录最大深度最左节点的数值。代码如下:
int maxDepth = INT_MIN; // 全局变量 记录最大深度
int result; // 全局变量 最大深度最左节点的数值
void traversal(TreeNode* root, int depth)
2. 结束条件
当遇到叶子节点的时候,就需要统计一下最大的深度了,所以需要遇到叶子节点来更新最大深度。
3. 在找最大深度的时候,递归的过程中依然要使用回溯。
详细代码如下:
class Solution {
public:
int res;
int max_depth = -1;
void dfs(TreeNode* root, int depth)
{
if(root->left==nullptr&&root->right==nullptr)
{
if(depth>max_depth)
{
max_depth = depth;
res = root->val;
}
return ;
}
if(root->left) dfs(root->left, depth+1); //带有回溯
if(root->right) dfs(root->right, depth+1);
}
int findBottomLeftValue(TreeNode* root) {
//递归法 核心思路是最左边的节点就是第一个深度变大的节点之一
dfs(root,0);
return res;
}
};
112. 路径总和
这道题目返回bool值,所以我的思路是使用后序遍历来做,遍历完后返回根节点的结果,递归三步走:
1. 参数: 返回类型就是bool,需要的参数有节点和tatget与各个节点的差,不用再另写函数;
2. 结束条件:如果节点为空,说明没找到符合条件的路径,返回空;如果当前节点不为空,但是当前target==root->val,且当前节点是叶子节点,返回true;否则false;
3. 处理每层逻辑:
后序遍历,然后返回左右子树的逻辑或,这样有一条路径就可返回true
详细代码如下:
class Solution {
public:
bool hasPathSum(TreeNode* root, int targetSum) {
if(root==nullptr) return false;//结束条件
if(root->left==nullptr&&root->right==nullptr)
{
if(targetSum==root->val) return true;
return false;
}
//每层逻辑 后序
bool left = hasPathSum(root->left,targetSum-root->val); //左
bool right = hasPathSum(root->right, targetSum-root->val); //右
return left||right; //中
}
};
总结小tips:
递归函数什么时候需要返回值?什么时候不需要返回值?这里总结如下三点:
- 如果需要搜索整棵二叉树且不用处理递归返回值,递归函数就不要返回值。(这种情况如113.路径总和ii)
- 如果需要搜索整棵二叉树且需要处理递归返回值,递归函数就需要返回值。 (这种情况在236. 二叉树的最近公共祖先 (opens new window)中介绍)
- 如果要搜索其中一条符合条件的路径,那么递归一定需要返回值,因为遇到符合条件的路径了就要及时返回。(本题的情况)
113.路径总和II
这道题目和112十分相似,但是这道题需要返回每个路径,不能找到一条就返回了,要把所有的路径都遍历完,递归三步走:
1. 参数:
不需要返回参数,传入的参数则需要有一个记录当前路径的以及节点,以及一个储存结果的变量:
2. 结束条件:
遇到叶子节点且求和符合条件,就把path加入到结果变量res中;
3. 每层逻辑:
根左右;
我自己写了思路,但是不能AC,错误代码如下:
class Solution {
public:
vector<vector<int>> res;
void dfs(TreeNode* root, int targetSum, vector<int>& path)
{
if(root==nullptr) return ;
path.push_back(root->val); //中
if(root->left==nullptr&&root->right==nullptr)
{
if(root->val==targetSum)
{
res.push_back(path);
}
return ;
}
dfs(root->left,targetSum-root->val,path);
path.pop_back();
dfs(root->right, targetSum-root->val,path);
path.pop_back();
}
vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
vector<int> path;
dfs(root,targetSum,path);
return res;
}
};
进行代码随想录学习,发现我的问题在于:我的回溯出了问题,因为我没有判断左节点和右节点的合理性,所以会出现加入左节点等于null时,回溯停止,但是依据上述代码,path多pop了一个元素,所以要改正代码,需要把push和pop进行配对出现,简单改正后可以AC的代码如下:
class Solution {
public:
vector<vector<int>> res;
void dfs(TreeNode* root, int targetSum, vector<int>& path)
{
if(root==nullptr) return ;
path.push_back(root->val); //中
if(root->left==nullptr&&root->right==nullptr)
{
if(root->val==targetSum)
{
res.push_back(path);
}
return;
}
if(root->left)
{
dfs(root->left,targetSum-root->val,path);
path.pop_back(); //这里注意配对
}
if(root->right){
dfs(root->right, targetSum-root->val,path);
path.pop_back(); //这里也要注意
}
}
vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
vector<int> path;
dfs(root,targetSum,path);
return res;
}
};
106. 从中序与后序遍历序列构造二叉树
这道题目以前做过,但是思路忘记了,再学习代码随想录总结一遍,直接使用索引的效率高:
-
第一步:如果数组大小为零的话,说明是空节点了。
-
第二步:如果不为空,那么取后序数组最后一个元素作为节点元素。
-
第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点
-
第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)
-
第五步:切割后序数组,切成后序左数组和后序右数组
-
第六步:递归处理左区间和右区间
详细代码如下:
class Solution {
public:
TreeNode* dfs(vector<int> inorder, int il,int ir, vector<int> postorder,int pl, int pr)
{
//结束条件
if(il==ir) return nullptr;
int x = postorder[pr-1];//最后一个元素
TreeNode* root = new TreeNode(x);
if(pr-pl==1) return root;
//找到中序数组中的索引
int index;
for(int i=il;i<ir;i++)
{
if(inorder[i]==x)
{
index=i;
break;
}
}
//切割中序数组
int lenr = index-il; //左子树的长度
int left_in_beg = il;
int left_in_end = index;
int right_in_beg = index+1;
int right_in_end = ir;
//切割后序数组
int left_po_beg = pl;
int left_po_end = pl+lenr;
int right_po_beg = left_po_end;
int right_po_end = pr-1;
//递归
root->left = dfs(inorder, left_in_beg, left_in_end, postorder, left_po_beg, left_po_end);
root->right = dfs(inorder, right_in_beg, right_in_end, postorder, right_po_beg, right_po_end);
return root; //中
}
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
//后序遍历
if(inorder.size()!=postorder.size()) return nullptr;
return dfs(inorder,0,inorder.size(),postorder,0,postorder.size());
}
};