1、找二叉树左下角的值:递归法重新思考;迭代法就是模板
2、二叉树路径和:
求匹配,如果题目要求匹配就结束,在递归中需要返回值,来提前结束寻找;
如果题目中要求遍历二叉树,不能提前结束寻找,使用res记录无需返回值。
3、从中序遍历与后序遍历序列构建二叉树:
需要反复思考递归的返回、输入、停止、单次逻辑
题目链接:513. 找树左下角的值 - 力扣(LeetCode)
二叉树左下角的值其实本质上就是最后一层的第一个值
思路1:使用层序遍历迭代法,获取获取每一层的第一个值,覆盖掉上一层的第一个值。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int findBottomLeftValue(TreeNode* root) {
//使用层序遍历,迭代法
queueque;
int res;
if(root==nullptr)return 0;
que.push(root);
while(!que.empty())
{
int size =que.size();
for(int i=0;ival;
if(cur->left!=nullptr)que.push(cur->left);
if(cur->right!=nullptr)que.push(cur->right);
}
}
return res;
}
};
思路2:使用递归法:本质上其实在找最深层的第一个节点,深度是从根节点到叶子节点->从上往下->使用前序遍历+回溯的方法
1、确定递归的返回参数、传入参数
找二叉树的深度的时候,是从上往下,不易使用返回值记录每一层的特点,而是直接使用一个变量去记录便于回溯。
传入当前节点、深度,使用一个全局深度与当前层深度(从-1开始,因为0层表示叶子节点)对比
int max_depth=-1;
int res;
//递归遍历
//1、确定返回值、输入参数
//因为是求最下边的最左节点,深度使用前序遍历+回溯
//无需返回值,深度是从上往下底层,不易返回,使用一个变量记录,与全局深度比较
//输入参数:当前节点,深度(与全局深度比较)
void digui(TreeNode* root,int depth)
2、确定递归的停止条件
前序遍历->寻找最下边的某些东西,停止条件满足后->意味指到达最下边,需要记录满足的东西,之后进行回溯
这里到达叶子节点后:需要判断深度与最大深度的关系,决定左下角节点的值的变化
//2、确定停止条件
//寻找左节点,前序遍历会记录当前位置,所以只需要到叶子节点
if(root->left==nullptr&&root->right==nullptr)//叶子节点,需要记录与判断
{
//判断深度,因为是优先左节点,再右节点,只有深度变化,才会记录最左边的值
if(max_depthval;
max_depth =depth;//更新最大深度
}
}
3、确定递归的单层逻辑循环
前序遍历:中左右,中无需记录,直接跳过,左遍历,回溯,右遍历,回溯
//3、确定单层循环逻辑
//中左右
//不需要记录中,因为在寻找最下的元素
//递归左,没有判断是不是空,所以需要自己判断
if(root->left!=nullptr)
{
//深度
depth++;
//递归
digui(root->left,depth);
//回溯
depth--;
}
//递归右,没有判断是不是空,所以需要自己判断
if(root->right!=nullptr)
{
//深度
depth++;
//递归
digui(root->right,depth);
//回溯
depth--;
}
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int max_depth=-1;
int res;
//递归遍历
//1、确定返回值、输入参数
//因为是求最下边的最左节点,深度使用前序遍历+回溯
//无需返回值,深度是从上往下底层,不易返回,使用一个变量记录,与全局深度比较
//输入参数:当前节点,深度(与全局深度比较)
void digui(TreeNode* root,int depth)
{
//2、确定停止条件
//寻找左节点,前序遍历会记录当前位置,所以只需要到叶子节点
if(root->left==nullptr&&root->right==nullptr)//叶子节点,需要记录与判断
{
//判断深度,因为是优先左节点,再右节点,只有深度变化,才会记录最左边的值
if(max_depthval;
max_depth =depth;//更新最大深度
}
}
//3、确定单层循环逻辑
//中左右
//不需要记录中,因为在寻找最下的元素
//递归左,没有判断是不是空,所以需要自己判断
if(root->left!=nullptr)
{
//深度
depth++;
//递归
digui(root->left,depth);
//回溯
depth--;
}
//递归右,没有判断是不是空,所以需要自己判断
if(root->right!=nullptr)
{
//深度
depth++;
//递归
digui(root->right,depth);
//回溯
depth--;
}
}
int findBottomLeftValue(TreeNode* root) {
digui(root,0);
return res;
}
};
题目链接:112. 路径总和 - 力扣(LeetCode)
求路径匹配,可以使用前序遍历+回溯(递归)
返回参数:因为这个题要求匹配后就可以输出答案,所以返回true\false
传入参数:当前节点、匹配值、当前的和(通过设置全局和无需传入)
int sum = 0;
//寻找路径,可以使用前序遍历+回溯
//1、确定递归返回值,输入值
//返回值:如果
//输入值:当前节点,一个sum,用于记录当前路径的和,目标值,
bool digui(TreeNode* root,int &targetSum)
停止条件:前序遍历,一般在获取叶子节点后开始判断记录
(1)首先刚到叶子节点,需要将叶子节点的值加入到sum中
(2)判断sum是不是==目标值
(3)等于返回true,不等于返回false
//2、确定停止条件
//当遇到叶子节点,表示当前路径寻找完毕,需要判断当前路径是不是等于目标值
if(root->left==nullptr&&root->right==nullptr)
{
sum += root->val;
if(sum == targetSum)
{
return true;
}
else
{
return false;
}
}
前序遍历+回溯:
(1)中:首先将当前节点值加入到sum中;
(2)左:递归左子节点,如果左子节点的返回值是true,直接返回true,如果是false需要回溯,往下运行
(3)右:递归右子节点,如果右子节点的返回值是true,直接返回true,如果是false需要回溯,往下运行
(4)最后,返回false,因为左右子节点递归都不满足
//3、确定单层递归逻辑
//前序遍历+回溯,中左右,记录sum
sum += root->val;//记录当前节点的值
//左子节点遍历,因为没有保护左子节点==nullptr,需要在这里设置
if(root->left!=nullptr)
{
if(digui(root->left,targetSum)==true) return true;
//如果没找到,回溯
sum -= root->left->val;
}
if(root->right!=nullptr)
{
if(digui(root->right,targetSum)==true)return true;
//如果没找到,回溯
sum -= root->right->val;
}
return false;
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int sum = 0;
//寻找路径,可以使用前序遍历+回溯
//1、确定递归返回值,输入值
//返回值:如果
//输入值:当前节点,一个sum,用于记录当前路径的和,目标值,
bool digui(TreeNode* root,int &targetSum)
{
//2、确定停止条件
//当遇到叶子节点,表示当前路径寻找完毕,需要判断当前路径是不是等于目标值
if(root->left==nullptr&&root->right==nullptr)
{
sum += root->val;
if(sum == targetSum)
{
return true;
}
else
{
return false;
}
}
//3、确定单层递归逻辑
//前序遍历+回溯,中左右,记录sum
sum += root->val;//记录当前节点的值
//左子节点遍历,因为没有保护左子节点==nullptr,需要在这里设置
if(root->left!=nullptr)
{
if(digui(root->left,targetSum)==true) return true;
//如果没找到,回溯
sum -= root->left->val;
}
if(root->right!=nullptr)
{
if(digui(root->right,targetSum)==true)return true;
//如果没找到,回溯
sum -= root->right->val;
}
return false;
}
bool hasPathSum(TreeNode* root, int targetSum) {
if(root==nullptr)return false;
return digui(root,targetSum);
}
};
题目链接:113. 路径总和 II - 力扣(LeetCode)
与上一题不同,这个是匹配所有的路径,所以需要遍历整棵二叉树,将满足的路径保存,所以不需要返回值,但是同样的思路:前序遍历+回溯
返回值:因为是遍历整棵二叉树,记录路径使用全局变量vector,无需返回值
输入值:当前节点、目标值
//1、确定返回值、输入值
//返回值:无需返回值,路径使用全局变量记录
//输入值:当前节点、目标值、(当前值为多少也使用全局变量记录,当前路径也使用全局变量记录)
void digui(TreeNode* root,int targetSum)
{
因为是前序遍历+回溯寻找路径,找到叶子节点就可以停止,开始将当前路径判断和是不是等于目标值,等于目标值记录,不等于目标值舍弃
//2、确定停止条件
//停止条件:叶子节点就记录路径、判断路径和
if(root->left==nullptr&&root->right==nullptr)
{
//存储当前的叶子节点
sum +=root->val;
path.push_back(root->val);
//判断是不是等于目标和
if(sum ==targetSum)
{
//记录到res中
res.push_back(path);
return;
}
//如果不是,就return
return ;
}
前序遍历+回溯:
路径中加入当前节点
递归左子节点,回溯
递归右子节点,回溯
//3、确定单层递归逻辑
//记录中节点
sum+=root->val;
path.push_back(root->val);
//递归左右节点,在左右节点!=nullptr下
if(root->left!=nullptr)
{
digui(root->left,targetSum);
//回溯
sum -=root->left->val;
path.pop_back();
}
if(root->right!=nullptr)
{
digui(root->right,targetSum);
//回溯
sum -=root->right->val;
path.pop_back();
}
return ;
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector>res;
vectorpath;
int sum=0;
//1、确定返回值、输入值
//返回值:无需返回值,路径使用全局变量记录
//输入值:当前节点、目标值、(当前值为多少也使用全局变量记录,当前路径也使用全局变量记录)
void digui(TreeNode* root,int targetSum)
{
//2、确定停止条件
//停止条件:叶子节点就记录路径、判断路径和
if(root->left==nullptr&&root->right==nullptr)
{
//存储当前的叶子节点
sum +=root->val;
path.push_back(root->val);
//判断是不是等于目标和
if(sum ==targetSum)
{
//记录到res中
res.push_back(path);
return;
}
//如果不是,就return
return ;
}
//3、确定单层递归逻辑
//记录中节点
sum+=root->val;
path.push_back(root->val);
//递归左右节点,在左右节点!=nullptr下
if(root->left!=nullptr)
{
digui(root->left,targetSum);
//回溯
sum -=root->left->val;
path.pop_back();
}
if(root->right!=nullptr)
{
digui(root->right,targetSum);
//回溯
sum -=root->right->val;
path.pop_back();
}
return ;
}
vector> pathSum(TreeNode* root, int targetSum) {
//确保root不空
if (root==nullptr)return res;
digui(root,targetSum);
return res;
}
};
题目链接:106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode)
中序:左中右
后序:左右中
通过后序数组的最后一位可以获得中间的节点,在中序数组中找到中间节点,左边的就是左子树,右边的就是右子树-->将中序数组通过中点分割成左中序数组、右中序数组,同样将后序数组的最后一位(当前中间节点)去掉,将后序数组分为左后序数组、右后序数组(根据左右子树元素相等)之后进行递归。。。
返回参数:最终要求返回的是构造的二叉树,所以要返回每一次的节点
传入参数:传入每次划分的中序数组、后序数组
//递归获取每一个位置上的节点:
//1、确定递归的输入参数、返回参数
//返回参数:返回根节点的完整二叉树
//输入参数:后序遍历数组、中序遍历数组
TreeNode* digui(vector& inorder,vector&postorder)
当中序(后序)数组为空,就返回nullptr,表示叶子节点下边的空节点
if(postorder.size()==0)return nullptr;
//(1)获取后序遍历数组的尾元素-->中间节点
TreeNode* root = new TreeNode();
root->val = postorder[postorder.size()-1];
for(;ival)
break;//此时i就是中间节点在中序遍历数组中的下标位置
}
vectorleft_inorder (inorder.begin(),inorder.begin()+i);//将中序遍历数组切割成左中序遍历数组,开始到i的前一位,注意是左闭右开
vectorright_inorder (inorder.begin()+i+1,inorder.end());//将中序遍历数组切割成右中序遍历数组,中序遍历数组的i后第一位置,到最后
//切割后序遍历数组,中序、后序的数组子树元素相同
vectorleft_postorder (postorder.begin(),postorder.begin()+i);
vectorright_postorder (postorder.begin()+i,postorder.end()-1);
//递归左子树,递归右子树
root->left = digui(left_inorder,left_postorder);
root->right =digui(right_inorder,right_postorder);
return root;
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
//递归获取每一个位置上的节点:
//1、确定递归的输入参数、返回参数
//返回参数:返回根节点的完整二叉树
//输入参数:后序遍历数组、中序遍历数组
TreeNode* digui(vector& inorder,vector&postorder)
{
//2、确定递归的停止条件:
//如果后序遍历数组是空的,表示根节点是nullptr
if(postorder.size()==0)return nullptr;
//3、确定单层递归逻辑
//(1)获取后序遍历数组的尾元素-->中间节点
TreeNode* root = new TreeNode();
root->val = postorder[postorder.size()-1];
//(2)切割中序遍历数组,从开始到中间节点之前、中间结点之后到结束
int i = 0;
for(;ival)
break;//此时i就是中间节点在中序遍历数组中的下标位置
}
vectorleft_inorder (inorder.begin(),inorder.begin()+i);//将中序遍历数组切割成左中序遍历数组,开始到i的前一位,注意是左闭右开
vectorright_inorder (inorder.begin()+i+1,inorder.end());//将中序遍历数组切割成右中序遍历数组,中序遍历数组的i后第一位置,到最后
//切割后序遍历数组,中序、后序的数组子树元素相同
vectorleft_postorder (postorder.begin(),postorder.begin()+i);
vectorright_postorder (postorder.begin()+i,postorder.end()-1);
//递归左子树,递归右子树
root->left = digui(left_inorder,left_postorder);
root->right =digui(right_inorder,right_postorder);
return root;
}
TreeNode* buildTree(vector& inorder, vector& postorder) {
return digui(inorder,postorder);
}
};