Day13 OK,继续追大前天的打卡!第十三天
以下是今日份的总结
513 找树左下角的值
112 路径总和
113 路径总和ii
106 从中序与后序遍历序列构造二叉树
105 从前序与中序遍历序列构造二叉树
513 层序遍历,只需要找到最后一层的第一个节点
112 回溯的思想
113 同上
106 中序和后序确认一棵二叉树
105 同上
今天的题目难度不低,但是也不难想,跟着随想录码一遍很容易就会了 ^ _ ^
找树左下角的值
思路:
深度最深的左叶子节点,没有左叶子节点时就是右叶子节点
层序遍历,只需要找到每一层的第一个节点
值得注意的是
递归和迭代法思路都是一样的
递归
void order(TreeNode* cur,vector<vector<int>>&vec,int depth){
if(cur==nullptr)return;
if(vec.size()==depth)vec.push_back(vector<int>());
vec[depth].push_back(cur->val);
order(cur->left,vec,depth+1);
order(cur->right,vec,depth+1);
}
int findBottomLeftValue(TreeNode* root) {
vector<vector<int>>res;//二维数组最下层的最左边的就是左下角的值
int depth = 0;
order(root, res, depth);
return res[res.size()-1][0];
}
迭代
int findBottomLeftValue(TreeNode* root) {
if (root == NULL)
return 0;
queue<TreeNode*> que;
que.push(root);
TreeNode* leftMost = root;
while (!que.empty()) {
//使用size 来保存当前层的节点数,确保我们在遍历当前层时不会受 que.size() 变化的影响。
int size = que.size();
for (int i = 0; i < size; i++) {
TreeNode* tmp = que.front();
que.pop();
if (i == 0)
leftMost = tmp;
if (tmp->left)
que.push(tmp->left);
if (tmp->right) {
que.push(tmp->right);
}
}
}
return leftMost->val;
}
路径总和
思路:
找从根节点到叶节点的路径,用到回溯,并在过程中计算路径上节点值的和是否等于targetSum
值得注意的是
数组越界问题,在左右子树的递归时对队列进行弹出操作,在叶节点判断的时候不需要,这样会导致数组越界;path.pop_back() 仅在递归回溯时调用一次,以确保路径管理正确。这样可以避免对已被删除的元素进行访问。
void road(TreeNode* cur,vector<int> &path,vector<int> &sum){
//中序遍历
path.push_back(cur->val);//中
//左
if(cur->left){
road(cur->left, path,sum);
path.pop_back();
}
//右
if(cur->right){
road(cur->right, path,sum);
path.pop_back();
}
//叶节点判断
if(cur->left==NULL&&cur->right==NULL){
int size = path.size(),sums = 0;
for(int i = 0;i<size;i++){
sums+=path[i];
}
sum.push_back(sums);
//path.pop_back();
return;
}
//path.pop_back();
}
bool hasPathSum(TreeNode* root, int targetSum) {
if(root == nullptr) return false;
vector<int> path;
vector<int> sum;
road(root,path,sum);
for(int i:sum){
if(i==targetSum)return true;
}
return false;
}
路径总和ii
思路:
找从根节点到叶节点的路径,用到回溯,并在过程中计算路径上节点值的和是否等于targetSum
值得注意的是
上一题是判断有没有路径总和为targetSum的路径,而这道题是找出有几条
void road(TreeNode* cur,vector<int> &path,vector<vector<int>> &sPath,int targetSum){
//中序遍历
path.push_back(cur->val);//中
//左
if(cur->left){
road(cur->left, path,sPath,targetSum);
//path.pop_back();
}
//右
if(cur->right){
road(cur->right,path,sPath,targetSum);
//path.pop_back();
}
//叶节点判断
if(cur->left==NULL&&cur->right==NULL){
int size = path.size(),sums = 0;
for(int i = 0;i<size;i++){
sums+=path[i];
}
if(sums==targetSum){
sPath.push_back(path);
}
//path.pop_back();错误,会造成多一次的元素弹出,数组越界
//return;
}
path.pop_back();
}
vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
if(root == NULL)return vector<vector<int>>();
vector<vector<int>> res;
vector<int>path;
road(root,path,res,targetSum);
return res;
}
从中序与后序遍历序列构造二叉树
思路:
根据后序遍历序列分割中序遍历序列,然后递归
值得注意的是
多层vector的创建影响效率,仍然可以优化更好的方法
TreeNode* traversal(vector<int>& inorder,vector<int>& postorder){
//1.做判空处理
if(postorder.size()==0) return NULL;
//2.后续遍历数组最后一位是当前的中间节点
int rootValue = postorder[postorder.size()-1];
TreeNode* root = new TreeNode(rootValue);//创建根结点
//发现是叶子节点
if(postorder.size()==1)return root;
//3.找切割点
int index;
for(index= 0;index<inorder.size();index++){
if(inorder[index]==rootValue)break;//得到当前在inorder数组中跟节点的位置
}
//4.切割中序数组,得到左右两个数组
vector<int> leftInorder(inorder.begin(),inorder.begin()+index);
vector<int> rightInorder(inorder.begin()+index+1,inorder.end());
//5.切割后续数组,得到左右两个数组
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());//已经舍弃末尾元素所以使用end
//6.递归
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);
}
从前序与中序遍历序列构造二叉树
思路:
根据前序遍历序列分割中序遍历序列,然后递归
值得注意的是
同上
TreeNode* traversal(vector<int>& preorder, vector<int>& inorder) {
// 1.做判空处理
if (preorder.size() == 0)
return NULL;
// 2.先序遍历数组第一位是当前的中间节点
int rootValue = preorder[0];
TreeNode* root = new TreeNode(rootValue); // 创建根结点
// 发现是叶子节点
if (preorder.size() == 1)
return root;
// 3.找切割点
int index;
for (index = 0; index < inorder.size(); index++) {
if (inorder[index] == rootValue)
break; // 得到当前在inorder数组中跟节点的位置
}
// 4.切割中序数组,得到左右两个数组
vector<int> leftInorder(inorder.begin(), inorder.begin() + index);
vector<int> rightInorder(inorder.begin() + index + 1, inorder.end());
// 5.切割先序数组,得到左右两个数组
vector<int>tmp (preorder.begin()+1,preorder.end());
preorder.resize(preorder.size() - 1); // 舍弃开头元素
preorder.clear();
preorder = tmp;
// [0, leftInorder.size)
vector<int> leftPreorder(
preorder.begin(),
preorder.begin() + leftInorder.size()); // 利用中序左数组的长度
// [leftInorder.size(), end)
vector<int> rightPreorder(
preorder.begin() + leftInorder.size(),
preorder.end()); // 已经舍弃末尾元素所以使用end
// 6.递归
root->left = traversal(leftPreorder, leftInorder);
root->right = traversal(rightPreorder, rightInorder);
// 返回
return root;
}
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
if(preorder.size()==0||inorder.size()==0)return NULL;
return traversal(preorder,inorder);
}
写在最后
----OK,今日份的博客就写到这里,这一期的题不轻松啊,明天继续加油!!!
—看了看下期的题,二叉树就没轻松的;
–追上时间进度了吗?如追,从欠四天变成欠三天!!(笑
-温柔藏在睫毛里👀。