513.找树左下角的值
题目链接/文章讲解/视频讲解:代码随想录
1.代码展示
//513找树左下角的值
int findResult;
int findMaxHeight = INT_MIN;
void findTravelsal(TreeNode* node, int& height) {
//step1 确定参数
//step2 确定终止条件
if (node->left == nullptr && node->right == nullptr) {
//此时为叶子节点
if (height > findMaxHeight) {
//更新最大高度,更新结果
findMaxHeight = height;
findResult = node->val;
return;
}
return;
}
//step3 确定单层迭代逻辑
//左子节点
if (node->left != nullptr) {
height++;
findTravelsal(node->left, height);
//回溯
height--;
}
//右子节点
if (node->right != nullptr) {
height++;
findTravelsal(node->right, height);
height--;
}
//中不需要做逻辑处理
return;
}
int findBottomLeftValue(TreeNode* root) {
int height = 0;
findTravelsal(root, height);
return findResult;
}
2.本题小节
主要思路:首先要明确左下角的值是在叶子节点处,同时递归到叶子节点也是终止条件,因此寻找左下角的值是在终止条件中寻找的,同时要注意,只有当前叶子节点的深度大于最大深度时,才能更新结果;其次要注意的是深度,每次递归时需要++,递归结束后需要回溯,高度--;最后要注意的是必须先左后右,只有这样,在同一深度下,才能优先找到左值。
112. 路径总和
题目链接/文章讲解/视频讲解:代码随想录
1.代码展示
//112.求总路径和
bool hasPathSumTravelsal(TreeNode* node, int targetSum) {
//step1 确定迭代参数
//step2 确定终止条件
if (node->left == nullptr && node->right == nullptr && targetSum == 0) {
//该路径符合条件
return true;
}
if (node->left == nullptr && node->right == nullptr && targetSum != 0) {
//该路径不符合条件
return false;
}
//step3 确定单层迭代逻辑
//左
if (node->left != nullptr) {
targetSum -= node->left->val;
bool isPathL = hasPathSumTravelsal(node->left, targetSum);
targetSum += node->left->val;
if (isPathL) {
return true;
}
}
//右
if (node->right != nullptr) {
targetSum -= node->right->val;
bool isPathR = hasPathSumTravelsal(node->right, targetSum);
targetSum += node->right->val;
if (isPathR) {
return true;
}
}
//非叶子节点或者左右两边都不符合
return false;
}
bool hasPathSum(TreeNode* root, int targetSum) {
if (root != nullptr) {
return hasPathSumTravelsal(root, targetSum - root->val);
}
else {
return false;
}
}
2.本题小节
主要思路:本题和“求根节点到叶子节点的路径”很像,首先要明确的是本题判断路径总和是在叶子节点中判断的,也就是在终止条件中判断的,有两种情况,一种是targetsum最终递归为0,那么返回为true,如果不为0,返回为false;然后需要注意的是本题也用到了回溯,进行左右子树递归前,先减掉左右子树的val,递归后,再加回来;最后要注意的是,只要找到一条满足路径综合条件的路径,就满足题意了,因此每次左右递归时,会进行判断,满足条件,就直接return true。
113.路径总和ii
1.代码展示
//113.路径总和Ⅱ
void pathSumTravelsal(TreeNode* node, int targetSum, vector<int>& vnPath, vector<vector<int>>& vvnTotalPath) {
//step1 确定参数
//step2 确定中止条件
if (node->left == nullptr && node->right == nullptr && targetSum == 0) {
//叶子节点且为目标路径
vvnTotalPath.push_back(vnPath);
return;
}
if (node->left == nullptr && node->right == nullptr && targetSum != 0) {
return;
}
//step3 确定单层迭代逻辑
//左
if (node->left != nullptr) {
targetSum -= node->left->val;
vnPath.push_back(node->left->val);
pathSumTravelsal(node->left, targetSum, vnPath, vvnTotalPath);
//回溯
targetSum += node->left->val;
vnPath.pop_back();
}
//右
if (node->right != nullptr) {
targetSum -= node->right->val;
vnPath.push_back(node->right->val);
pathSumTravelsal(node->right, targetSum, vnPath, vvnTotalPath);
//回溯
targetSum += node->right->val;
vnPath.pop_back();
}
return;
}
vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
vector<vector<int>> vvnTotalPath;
vector<int> vnPath;
if (root != nullptr) {
vnPath.push_back(root->val);
pathSumTravelsal(root, targetSum - root->val, vnPath, vvnTotalPath);
}
return vvnTotalPath;
}
2.本题小节
基本思路:这题是上一题的拓展,要把所有满足路径总和的结果都统计出来,就是上一题加上求“根节点到叶子节点的路径”的结合,比上题多了一个vec回溯,用来储存结果,在中止条件中,添加vec,不用在左右迭代处判断,因为这次是要统计所有的情况。
106.从中序与后序遍历序列构造二叉树
题目链接/文章讲解/视频讲解:代码随想录
1.代码展现
//106.从中序与后序遍历序列构造二叉树
TreeNode* buildTreeTravelal(vector<int>& inorder, vector<int>& postorder) {
//step1 确定参数
//step2 确定中止条件
//后序为空即初始就为空,则直接返回
if (postorder.size() == 0) {
return nullptr;
}
//创建父节点
int rootValue = postorder[postorder.size() - 1];
TreeNode* node = new TreeNode(rootValue);
//后序大小为1,则为叶子节点,返回该节点
if (postorder.size() == 1) {
return node;
}
//step3 确定单层遍历逻辑
//step3.1 分割中序数组
//从后序数组中找到父节点
int index;
//找到分割点
for (index = 0; index < inorder.size(); index++) {
if (rootValue == inorder[index]) {
break;
}
}
//左中序数组
vector<int> leftInorder(inorder.begin(), inorder.begin() + index);
//右中序数组
//vector<int> rightInorder(inorder.begin() + 1, inorder.end());
vector<int> rightInorder(inorder.begin() +index + 1, inorder.end());
//for (int i = 0; i < index + 1; i++) {
//for (int i = 0; i < index; i++) {
// leftInorder.push_back(inorder[i]);
//}
//右中序数组
//for (int i = index + 1; i < inorder.size(); i++) {
// rightInorder.push_back(inorder[i]);
//}
//step3.2 分割后序数组
//左后序数组
vector<int> leftPostorder(postorder.begin(), postorder.begin() + leftInorder.size());
//右后序数组
vector<int> rightPostorder(postorder.begin() + leftInorder.size(), postorder.end() - 1);
//左后序数组
//for (int i = 0; i < ind; i++) {
// leftPosorder.push_back(postorder[i]);
//}
右后序数组
//for (int i = ind; i < postorder.size() - 1; i++) {
// rightPosorder.push_back(postorder[i]);
//}
//step3.3 恢复节点左右子节点
node->left = buildTreeTravelal(leftInorder, leftPostorder);
node->right = buildTreeTravelal(rightInorder, rightPostorder);
return node;
}
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
if (inorder.size() == 0 || postorder.size() == 0) {
return nullptr;
}
return buildTreeTravelal(inorder, postorder);
}
2.本题小节
基本思路:本题的首先要搞懂如何从中序和后序遍历数组中恢复二叉树,并把这个过程用递归法展现出来。首先是确定递归函数,中序和后序数组;然后是确定终止条件,一个是当后序数组为空时,那么就递归完毕,直接返回nullptr,另外一种是当后序数组只有一个元素是,也就是叶子节点,直接返回该节点,但是在这之前,要用后序数组的最后一个元素来创建一个节点,作为后面递归的父节点,这个很重要;最后是单层迭代逻辑,也是重头戏,根据后序数组的最后一个元素从中序数组中找到该元素,并记录该元素的index,则开始分割,左边为左前序数组,右边为右前序数组,根据左前序数组的元素个数再从后序元素中分割数组为左后序数组,右后续数组,父节点的左子节点左前序数组和左后序数组进行递归,右子节点用右前序数组和右后序数组递归即可,最后返回父节点。
思考:不懂画图!!!注意分割方法,容器到容器用迭代器最方便!!!
105.从前序与中序遍历序列构造二叉树
1.代码展现
//105从中序与后序遍历序列构造二叉树
TreeNode* buildTreeTravelal(vector<int>& inorder, vector<int>& preorder) {
//step1 确定参数
//step2 确定中止条件
//前序为空即初始就为空,则直接返回
if (preorder.size() == 0) {
return nullptr;
}
//创建父节点
int rootValue = preorder[0];
TreeNode* node = new TreeNode(rootValue);
//后序大小为1,则为叶子节点,返回该节点
if (preorder.size() == 1) {
return node;
}
//step3 确定单层遍历逻辑
//step3.1 分割中序数组
//从后序数组中找到父节点
int index;
//找到分割点
for (index = 0; index < inorder.size(); index++) {
if (rootValue == inorder[index]) {
break;
}
}
//左中序数组
vector<int> leftInorder(inorder.begin(), inorder.begin() + index);
//右中序数组
vector<int> rightInorder(inorder.begin() + index + 1, inorder.end());
//左前序数组
vector<int> leftPretorder(preorder.begin() + 1, preorder.begin() + leftInorder.size() + 1);
//右前序数组
vector<int> rightPretorder(preorder.begin() + leftInorder.size() + 1, preorder.end());
//step3.3 恢复节点左右子节点
node->left = buildTreeTravelal(leftInorder, leftPretorder);
node->right = buildTreeTravelal(rightInorder, rightPretorder);
return node;
}
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
if (inorder.size() == 0 || preorder.size() == 0) {
return nullptr;
}
return buildTreeTravelal(inorder, preorder);
}
2.本题小节
基本思路:和上题一样,重点是理解前序中序如何恢复二叉树,对应修改创建的节点,以及分割逻辑即可,不再赘述。