day18
代码随想录
2023.12.16
1. 513找树左下角的值
这道题很直观的就是想到层序遍历,最后一层的第一个节点值就是我们需要的,而且很偷懒的是,不用判断是不是最后一层,每一层第一个节点值都保存,会覆盖,最后的值就是我们要的。
最后看代码随想录还讲了递归写法,就是在递归时加了个深度变量,最深且是左节点的就是我们要找的值,挺麻烦的,不细说了
/**
* 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) {
queue<TreeNode*> que;
if(root!=NULL) que.push(root);
int result;
while(!que.empty()){
int size = que.size();
for(int i=0;i<size;i++){
TreeNode*node = que.front();
que.pop();
if(i==0) result = node->val;
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
}
return result;
}
};
2. 112路经总和
这道题跟前几天做的一道所有路径很相似,那道题是将所有路径要要求打印出来,这是求和,思路是一样的,只是在最终路径处理上不同,这道题在叶子节点是将path的值全部相加,如果==targetsum,则返回true即可。
/**
* 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:
bool hasPathSum(TreeNode* root, int targetSum) {
vector<int> path;
if(root==NULL) return false;
return travel(root, path, targetSum);
}
bool travel(TreeNode*node, vector<int>& path, const int target){
path.push_back(node->val);
bool lefti=false;
bool righti=false;
if(node->left){
lefti=travel(node->left, path, target);
path.pop_back();
}
if(node->right){
righti=travel(node->right, path, target);
path.pop_back();
}
if(node->left==NULL && node->right==NULL){
int sum=0;
for(int i=0;i<path.size();i++){
sum +=path[i];
}
cout<<sum<<endl;
if(sum==target) return true;
}
return (lefti||righti);
}
};
3. 106从中序和后续遍历结果构造二叉树
这道题是这道时间遇到的最难一题了。拿到后有些没有头绪,手写结果很简单,没什么那难度,但代码实现就不知道怎么写了,看了代码随想录文字讲解,悟了一点;
首先明确,是要递归处理的,每次传入两个数组,构造子树。重点是就是函数的实现。每次递归都是以后序遍历的最后一个元素为重点的,该元素就是本次递归的根节点,以该节点为中心,将中序遍历划分为两个部分,就是下次递归的左右子树的中序遍历结果。所以中序遍历很好切割,思路就是,根据后序遍历找到中心点,再在中序遍历找到中心点的位置,以该位置分割中序遍历数组;那么,后续遍历怎么分割?后续遍历没有中序遍历那么明显的分割点,但要知道,中序遍历和后序遍历的数组大小是相等的,所以知道中序遍历分割结果,可以根据该结果去按大小分割后续遍历,但要注意顺序。最终得到两个中序遍历,两个后序遍历,在分别匹配传给递归函数构造本次递归函数的根节点的左右子树。即可
/**
* 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:
TreeNode* traversal (vector<int>& inorder, vector<int>& postorder) {
if (postorder.size() == 0) return NULL;
// 后序遍历数组最后一个元素,就是当前的中间节点
int rootValue = postorder[postorder.size() - 1];
TreeNode* root = new TreeNode(rootValue);
// 叶子节点
if (postorder.size() == 1) return root;
// 找到中序遍历的切割点
int delimiterIndex;
for (delimiterIndex = 0; delimiterIndex < inorder.size(); delimiterIndex++) {
if (inorder[delimiterIndex] == rootValue) break;
}
// 切割中序数组
// 左闭右开区间:[0, delimiterIndex)
vector<int> leftInorder(inorder.begin(), inorder.begin() + delimiterIndex);
// [delimiterIndex + 1, end)
vector<int> rightInorder(inorder.begin() + delimiterIndex + 1, inorder.end() );
// postorder 舍弃末尾元素
postorder.resize(postorder.size() - 1);
// 切割后序数组
// 依然左闭右开,注意这里使用了左中序数组大小作为切割点
// [0, leftInorder.size)
vector<int> leftPostorder(postorder.begin(), postorder.begin() + leftInorder.size());
// [leftInorder.size(), end)
vector<int> rightPostorder(postorder.begin() + leftInorder.size(), postorder.end());
root->left = traversal(leftInorder, leftPostorder);
root->right = traversal(rightInorder, rightPostorder);
return root;
}
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
if (inorder.size() == 0 || postorder.size() == 0) return NULL;
return traversal(inorder, postorder);
}
};