总结
关键是递归逻辑的书写,要明确前中后序遍历的逻辑,套进递归里
● 513.找树左下角的值
/*513. 找树左下角的值
中等
给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。
假设二叉树中至少有一个节点。*/
class Solution_513 {
public:
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) {}
};
/*
* 层序遍历用的是队列,头节点就是该层最左节点,只需判断是否为最后一层
*/
int findBottomLeftValue(TreeNode *root) {
int res = 0;
if (!root)
return res;
queue<TreeNode *> record;
record.push(root);
while (!record.empty()) {
int size = record.size();
int count = 0;
for (int i = 0; i < size; ++i) {
TreeNode *node = record.front();
record.pop();
if (i == 0)
res = node->val;
if (node->left)
record.push(node->left);
if (node->right)
record.push(node->right);
}
}
return res;
}
};
● 112. 路径总和
/*112. 路径总和
简单
给你二叉树的根节点 root 和一个表示目标和的整数 targetSum .
判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。
如果存在,返回 true ;否则,返回 false 。
叶子节点 是指没有子节点的节点。*/
class Solution_112 {
public:
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) {}
};
/*递归函数:返回值为根节点到叶子节点的高度是否等于指定值,输入参数为当前节点,指定值,路径和
终止条件:当前节点为叶子节点时,判断和是否相等,返回结果
递归逻辑:
前序遍历,中左右
1.和加上当前节点值
2.判断终止条件
3.递归左右节点*/
bool getPathSum(TreeNode *node, int targetSum, int path_sum) {
path_sum += node->val;
if (!node->left && !node->right) {
return path_sum == targetSum;
}
bool left_res{false};
bool right_res{false};
if (node->left)
left_res = getPathSum(node->left, targetSum, path_sum);
if (node->right)
right_res = getPathSum(node->right, targetSum, path_sum);
return (left_res | right_res);
}
bool hasPathSum(TreeNode *root, int targetSum) {
if(!root)
return false;
int sum = 0;
return getPathSum(root, targetSum, sum);
}
};
113.路径总和ii
/*113. 路径总和 II
中等
给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
叶子节点 是指没有子节点的节点。*/
class Solution_113 {
public:
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) {}
};
/*递归函数:返回值无,输入参数为当前节点,指定值,当前路径数组,结果数组
终止条件:当前节点为叶子节点时,判断和是否相等,如果相等结果数组添加当前路径数组
递归逻辑:前序遍历,中左右
1.当前路径数组加上当前节点值
2.判断终止条件
3.递归左右节点,注意输入参数均为引用,当前路径数组递归之后需要弹出最后一个节点,回溯到中节点,从而避免一个路径数组中记录了左右两个不可能同时到达的子节点
*/
void get_path(TreeNode *node, int targetSum,vector<int> &cur_path, vector<vector<int>> &res){
cur_path.push_back(node->val);
if (!node->left && !node->right) {
int path_sum = 0;
for(auto i : cur_path){
path_sum += i;
}
if(path_sum == targetSum){
res.push_back(cur_path);
}
return;
}
if (node->left) {
get_path(node->left, targetSum, cur_path, res);
cur_path.pop_back();//回溯到中节点
}
if (node->right) {
get_path(node->right, targetSum, cur_path, res);
cur_path.pop_back();//回溯到中节点
}
return;
}
vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
vector<vector<int>> res;
if(!root)
return res;
vector<int> path;
get_path(root, targetSum, path, res);
return res;
}
};
● 106.从中序与后序遍历序列构造二叉树
/*106. 从中序与后序遍历序列构造二叉树
中等
给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。
提示:
1 <= inorder.length <= 3000
postorder.length == inorder.length
-3000 <= inorder[i], postorder[i] <= 3000
inorder 和 postorder 都由 不同 的值组成
postorder 中每一个值都在 inorder 中
inorder 保证是树的中序遍历
postorder 保证是树的后序遍历
*/
class Solution_106 {
public:
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) {}
};
/*
* 输入参数为两个遍历数组,返回结果为根节点
终止条件为遍历数组剩一个元素,那需要保证传入参数不为空
单层递归逻辑:
先判断终止条件,若终止,返回根节点
先取后序数组最后一个元素作为根节点
通过该节点切割中序数组
根据切割得到的左右中序数组数量切割后序数组
左子树遍历,输入为左中序数组,左后序数组,返回为左子节点
右子树遍历,输入为右中序数组,右后序数组,返回为右子节点
返回根节点
*/
TreeNode *build_tree(vector<int> &inorder, vector<int> &postorder) {
//先取后序数组最后一个元素作为根节点
TreeNode *root = new TreeNode(*(postorder.end() - 1));
//终止条件为遍历数组剩一个元素,那需要保证传入参数不为空
if (inorder.size() == 1) {
return root;
}
//通过该节点切割中序数组
int mid_index = 0;
while (mid_index < inorder.size()) {
if (inorder[mid_index] == root->val)
break;
mid_index += 1;
}
vector<int> inorder_left(inorder.begin(), inorder.begin() + mid_index);//注意去掉已经用过的根节点
vector<int> inorder_right(inorder.begin() + mid_index + 1, inorder.end());
//根据切割得到的左右中序数组数量切割后序数组
vector<int> postorder_left(postorder.begin(), postorder.begin() + inorder_left.size());
vector<int> postorder_right(postorder.begin() + inorder_left.size(), postorder.end() - 1);//注意去掉已经用过的根节点
//左子树遍历,需要保证传入参数不为空
if (inorder_left.empty())
root->left = nullptr;
else
root->left = build_tree(inorder_left, postorder_left);
//右子树遍历,需要保证传入参数不为空
if (inorder_right.empty())
root->right = nullptr;
else
root->right = build_tree(inorder_right, postorder_right);
return root;
}
TreeNode *buildTree(vector<int> &inorder, vector<int> &postorder) {
if(inorder.size() == 0){
return nullptr;
}
return build_tree(inorder, postorder);
}
};
105.从前序与中序遍历序列构造二叉树
/*105. 从前序与中序遍历序列构造二叉树
中等
给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。*/
class Solution_105 {
public:
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) {}
};
/*
* 输入参数为两个遍历数组,返回结果为根节点
终止条件为遍历数组剩一个元素,那需要保证传入参数不为空
单层递归逻辑:
先判断终止条件,若终止,返回根节点
先取前序数组第一个元素作为根节点
通过该节点切割中序数组
根据切割得到的左右中序数组数量切割前序数组
左子树遍历,输入为左中序数组,左前序数组,返回为左子节点
右子树遍历,输入为右中序数组,右前序数组,返回为右子节点
返回根节点
*/
TreeNode *build(vector<int> &preorder, vector<int> &inorder){
//先取后序数组最后一个元素作为根节点
TreeNode *root = new TreeNode(*(preorder.begin()));
//终止条件为遍历数组剩一个元素,那需要保证传入参数不为空
if (inorder.size() == 1) {
return root;
}
//通过该节点切割中序数组
int mid_index = 0;
while (mid_index < inorder.size()) {
if (inorder[mid_index] == root->val)
break;
mid_index += 1;
}
vector<int> inorder_left(inorder.begin(), inorder.begin() + mid_index);//注意去掉已经用过的根节点
vector<int> inorder_right(inorder.begin() + mid_index + 1, inorder.end());
//根据切割得到的左右中序数组数量切割中序数组
vector<int> preorder_left(preorder.begin() + 1, preorder.begin() + inorder_left.size() + 1);//注意去掉已经用过的根节点
vector<int> preorder_right(preorder.begin() + inorder_left.size() + 1, preorder.end());
//左子树遍历,需要保证传入参数不为空
if (inorder_left.empty())
root->left = nullptr;
else
root->left = build(preorder_left, inorder_left);
//右子树遍历,需要保证传入参数不为空
if (inorder_right.empty())
root->right = nullptr;
else
root->right = build(preorder_right, inorder_right);
return root;
}
TreeNode *buildTree(vector<int> &preorder, vector<int> &inorder) {
if(inorder.size() == 0){
return nullptr;
}
return build(preorder, inorder);
}
};
● 513.找树左下角的值
● 112. 路径总和 113.路径总和ii
● 106.从中序与后序遍历序列构造二叉树 105.从前序与中序遍历序列构造二叉树