代码随想录算法训练营day16 | 513.找树左下角的值 、112.路径总和、113.路径总和Ⅱ、106.从中序与后序遍历序列构造二叉树、105.从前序与中序遍历序列构造二叉树
513.找树左下角的值
解法一:前序遍历
点击查看代码
class Solution {
public:
int maxDepth = 0;
int result;
void preOrder(TreeNode *root, int depth) {
if(root == nullptr) return;
if(depth > maxDepth) {
maxDepth = depth;
result = root->val;
}
preOrder(root->left, depth + 1);
preOrder(root->right, depth + 1);
}
int findBottomLeftValue(TreeNode* root) {
preOrder(root, 1);
return result;
}
};
无论前、中、后序,只要是先访问左子树后访问右子树的顺序,则在每一层中,必然是该层最左边的节点最先被处理,本题利用该点,使用前序遍历,当depth比maxdepth大时,说明该层第一次被访问处理,当前访问处理的就是该层最左边的节点,将其同步到result中,result会随着depth的增加而不断更新,最终维护的是depth最大(也即最底层)的一层的最左边的节点值
解法二:本题使用层序遍历亦非常合适
点击查看代码
class Solution {
public:
int findBottomLeftValue(TreeNode* root) {
int result;
queue<TreeNode*> que;
que.push(root);
while(!que.empty()) {
int size = que.size(); //核心语句,记录每层的节点个数
result = que.front()->val;
while(size-- > 0) {
TreeNode *cur = que.front();
que.pop();
if(cur->left) que.push(cur->left);
if(cur->right) que.push(cur->right);
}
}
return result;
}
};
112.路径总和
点击查看代码
class Solution {
public:
bool is_exist = 0;
void preOrder(TreeNode *root, int pathSum, int &targetSum) {
//if(root == nullptr) return;
if(root->left == nullptr && root->right == nullptr) {
if(pathSum == targetSum) is_exist = 1;
}
if(root->left) {
preOrder(root->left, pathSum + root->left->val, targetSum);
}
if(root->right) {
preOrder(root->right, pathSum + root->right->val, targetSum);
}
}
bool hasPathSum(TreeNode* root, int targetSum) {
if(root) {
preOrder(root, root->val, targetSum);
}
return is_exist;
}
};
本题思想与257.二叉树的所有路径的思想、做法基本一致,将根节点到子节点的路径总和通过参数传递逐层往下传,每层函数、每个节点维护各自到根节点的路经总和
113.路径总和Ⅱ
点击查看代码
class Solution {
public:
vector<vector<int>> result;
vector<int> addVal(vector<int> path, int num) { //往vector<int>容器里追加int型数据并返回拷贝值
path.push_back(num);
return path;
}
void preOrder(TreeNode *root, vector<int> path, int pathSum, int &targetSum) {
//if(root == nullptr) return;
if(root->left == nullptr && root->right == nullptr) {
if(pathSum == targetSum) result.push_back(path);
}
if(root->left) {
preOrder(root->left, addVal(path, root->left->val), pathSum + root->left->val, targetSum);
}
if(root->right) {
preOrder(root->right, addVal(path, root->right->val), pathSum + root->right->val, targetSum);
}
}
vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
if(root) {
vector<int> v;
v.push_back(root->val);
preOrder(root, v, root->val, targetSum);
}
return result;
}
};
106.从中序与后序遍历序列构造二叉树(难)
点击查看代码
class Solution {
public:
//区间均采用左闭右开区间,寻找子树的根节点,并将根节点与其左右子树连起来,最后返回该子树
TreeNode *searchRoot(vector<int> &inorder, int inLeft, int inRight, vector<int> &postorder, int postLeft, int postRight) {
//步骤一:从后序序列中找该子树的根节点
if(postLeft == postRight) return nullptr; //空树的根为nullptr
int rootVal = postorder[postRight - 1];
TreeNode *root = new TreeNode(rootVal);
if(postRight - postLeft == 1) return root; //叶子节点直接返回,无需连左右子树
//步骤二:用此根节点对中序序列划分为 左 根 右
int indivpoint;
for(indivpoint = inLeft; indivpoint < inRight; ++indivpoint) {
if(inorder[indivpoint] == rootVal) break;
}
int inleftBegin = inLeft, inleftEnd = indivpoint;
int inrightBegin = indivpoint + 1, inrightEnd = inRight;
//步骤三:对后序序列划分为 左 右 根
int postleftBegin = postLeft, postleftEnd = postLeft + (inleftEnd - inleftBegin);
//此处-1是去除了最后一个元素,因为其已经作为根节点
int postrightBegin = postleftEnd, postrightEnd = postRight - 1;
//步骤四:通过左子树的中序和后序序列找当前根节点的左子树的根节点,并让根节点和它的左子树连起来
root->left = searchRoot(inorder, inleftBegin, inleftEnd, postorder, postleftBegin, postleftEnd);
//步骤五:通过右子树的中序和后序序列找当前根节点的右子树的根节点,并让根节点和它的右子树连起来
root->right = searchRoot(inorder, inrightBegin, inrightEnd, postorder, postrightBegin, postrightEnd);
//步骤五:返回找到的本子树的根节点
return root;
}
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
return searchRoot(inorder, 0, inorder.size(), postorder, 0, postorder.size());
}
};
105.从前序与中序遍历序列构造二叉树
点击查看代码
class Solution {
public:
//区间均采用左闭右开区间,寻找子树的根节点,并将根节点与其左右子树连起来,最后返回该子树
TreeNode *searchRoot(vector<int> &preorder, int preLeft, int preRight, vector<int> &inorder, int inLeft, int inRight) {
//步骤一:从前序序列中找该子树的根节点
if(preLeft == preRight) return nullptr; //空树的根为nullptr
int rootVal = preorder[preLeft];
TreeNode *root = new TreeNode(rootVal);
if(preRight - preLeft == 1) return root; //叶子节点直接返回,无需连左右子树
//步骤二:用此根节点对中序序列划分为 左 根 右
int indivpoint;
for(indivpoint = inLeft; indivpoint < inRight; ++indivpoint) {
if(inorder[indivpoint] == rootVal) break;
}
int inleftBegin = inLeft, inleftEnd = indivpoint;
int inrightBegin = indivpoint + 1, inrightEnd = inRight;
//步骤三:对前序序列划分为 根 左 右 ,此处+1是去除了第一个元素,因为其已经作为根节点
int preleftBegin = preLeft + 1, preleftEnd = preLeft + 1 + (inleftEnd - inleftBegin);
int prerightBegin = preleftEnd, prerightEnd = preRight;
//步骤四:通过左子树的前序和中序序列找当前根节点的左子树的根节点,并让根节点和它的左子树连起来
root->left = searchRoot(preorder, preleftBegin, preleftEnd, inorder, inleftBegin, inleftEnd);
//步骤五:通过右子树的前序和中序序列找当前根节点的右子树的根节点,并让根节点和它的右子树连起来
root->right = searchRoot(preorder, prerightBegin, prerightEnd, inorder, inrightBegin, inrightEnd);
//步骤五:返回找到的本子树的根节点
return root;
}
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
return searchRoot(preorder, 0, preorder.size(), inorder, 0, inorder.size());
}
};
执行过程:根节点是从上往下找的,树的连接是从下往上连的,即下层连接完成后,再连往上层,最终整体连接完毕,返回整棵树的根节点
2025/02/28

浙公网安备 33010602011771号