代码随想录算法训练营第16天| 513. 找树左下角的值、112. 路径总和、113. 路径总和ii、106.从中序与后序遍历序列构造二叉树、105.从前序与中序遍历序列构造二叉树


513. 找树左下角的值

题目链接:513. 找树左下角的值

思想:这次用了迭代法,使用队列实现,按照根右左的顺序实现。最后出队的是树最深层最左边的值。递归的方法还没有掌握,应该是前序遍历然后如果碰到新的深度则替换原有的左下角值。

class Solution {
public:
    int findBottomLeftValue(TreeNode* root) {
        //迭代 广度优先遍历
        queue<TreeNode*> que;
        que.push(root);
        vector<int> ans;
        while(!que.empty()){
            if(que.front()!=nullptr){
                TreeNode* temp=que.front();
                ans.push_back(temp->val);
                if(temp->right!=nullptr)que.push(temp->right);
                if(temp->left!=nullptr)que.push(temp->left);
                que.pop();
            }
        }
        return *(ans.end()-1);
    }
};

112. 路径总和

题目链接:112. 路径总和

思想:碰到左右孩子为空的节点就往定义的vector数组里存入一次和。这道题主要要注意的是回溯的思路,在什么时候加入val,在什么时候减去val。也可以不做改变,直接把变化写在函数的参数里也可以,这样做掩藏了回溯的过程。还有一个要注意的是,相比于访问到最后一个节点时检查sum是否等于target,直接把初始值设为target然后访问每一层都减去对应的val然后查看末尾值是否等于0,代码可以少些很多。

class Solution {
public:
    bool hasPathSum(TreeNode* root, int targetSum) {
        vector<int> ans;
        int sum = 0;
        tranversal(root,sum,ans);
        for(int i=0;i<ans.size();i++){
            if(ans[i]==targetSum) return true;
        }
        return false;
    }

    void tranversal(TreeNode* root, int& sum, vector<int>& ans){
        if(root==nullptr) return;
        sum+=root->val;
        if(root->left==nullptr&&root->right==nullptr) ans.push_back(sum);
    
        tranversal(root->left,sum,ans);
        tranversal(root->right,sum,ans);
        sum-=root->val;
    }
};

113. 路径总和ii

题目链接:113. 路径总和 II

思想:和112.路径总和i的思想一样,但是这次更明显地突出了回溯的使用。在到达叶子节点时如果发现最后的结果不等于目标值,则需要回退到上一层,在此之前我们要先把在这一层放进数组中的值pop_back出来。

class Solution {
public:
    vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
        
        
        vector<int> ans;
        vector<vector<int>> res;
        if(root==nullptr) return res;
        ans.push_back(root->val);
        targetSum-=root->val;
        visit(root,targetSum,res,ans);
        return res;
    }

    void visit(TreeNode* root, int targetSum, vector<vector<int>>& res, vector<int> ans){
        if(root->left==nullptr&&root->right==nullptr&&targetSum==0){
            res.push_back(ans);
        }
        if(root->left==nullptr&&root->right==nullptr){
            return;           
        }

        if(root->left){
            ans.push_back(root->left->val);
            int temp = targetSum-root->left->val;            
            visit(root->left,temp,res,ans);
            ans.pop_back();
        }
        if(root->right){
            ans.push_back(root->right->val);
            int temp = targetSum-root->right->val;   
            visit(root->right,temp,res,ans);
            ans.pop_back();
        }
    }
};

106.从中序与后序遍历序列构造二叉树

题目链接:106. 从中序与后序遍历序列构造二叉树

思想:首先要明确怎么才能找到根节点,后序遍历数组中的最后一个元素就是根节点,在我们找到这个值之后,我们设置index来记录这个根节点在中序遍历序列中的什么部位。由于根节点把这个数组分成了两段,分别是左子树和右子树,所以我们也要通过递归分开处理。确定了这些之后,我们可以建立新的左子树的后序遍历数组和中序遍历数组,以及新的右子树的后序遍历数组和中序遍历数组。在这里我们需要注意的是必须先找出中序遍历数组,因为我们并不知道在后续遍历序列中,两个子树的间隔在什么地方,只能通过index来找。

class Solution {
public:
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        // 递归中止条件
        if (postorder.size() == 0)
            return nullptr;
        TreeNode* root = new TreeNode;
        if (postorder.size() == 1){
            root->val = postorder[postorder.size() - 1];
            return root;
        }            
        // 找到分开左右孩子的根节点的下标
        int index;
        for (index = 0; index < inorder.size(); index++) {
            if (inorder[index] == postorder[postorder.size() - 1])
                break;
        }
        root->val = postorder[postorder.size() - 1];
        // 新的中序遍历数组
        vector<int> new_inorder1(inorder.begin(), inorder.begin() + index);
        vector<int> new_inorder2(inorder.begin() + index + 1, inorder.end());
        // 新的后序遍历数组
        vector<int> new_postorder1(postorder.begin(), postorder.begin() + index);
        vector<int> new_postorder2(postorder.begin() + index, postorder.end() - 1);

        // 左右孩子
        root->left = buildTree(new_inorder1,new_postorder1);
        root->right = buildTree(new_inorder2,new_postorder2);
        return root;
        // 先找后序遍历的根节点
        //
    }
};

105.从前序与中序遍历序列构造二叉树

题目链接:105. 从前序与中序遍历序列构造二叉树

思想:同前一题,注意还是先分割中序遍历数组再分割前序遍历数组,创建新数组时要注意边界的把控.

class Solution {
public:
    TreeNode* buildTree( vector<int>& preorder, vector<int>& inorder) {
        // 递归中止条件
        if (preorder.size() == 0)
            return nullptr;
        TreeNode* root = new TreeNode;
        if (preorder.size() == 1){
            root->val = preorder[preorder.size() - 1];
            return root;
        }            
        // 找到分开左右孩子的根节点的下标
        int index;
        for (index = 0; index < inorder.size(); index++) {
            if (inorder[index] == preorder[0])
                break;
        }
        root->val = preorder[0];
        // 新的中序遍历数组
        vector<int> new_inorder1(inorder.begin(), inorder.begin() + index);
        vector<int> new_inorder2(inorder.begin() + index + 1, inorder.end());
        // 新的前序遍历数组
        vector<int> new_preorder1(preorder.begin()+1, preorder.begin() + index+1);
        vector<int> new_preorder2(preorder.begin()+1 + index, preorder.end());

        // 左右孩子
        root->left = buildTree(new_preorder1, new_inorder1);
        root->right = buildTree(new_preorder2, new_inorder2);
        return root;
        // 先找后序遍历的根节点
        //
    }
};

  • 7
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
代码随想录算法训练营是一个优质的学习和讨论平台,提供了丰富的算法训练内容和讨论交流机会。在训练营中,学员们可以通过观看视频讲解来学习算法知识,并根据讲解内容进行刷题练习。此外,训练营还提供了刷题建议,例如先看视频、了解自己所使用的编程语言、使用日志等方法来提高刷题效果和语言掌握程度。 训练营中的讨论内容非常丰富,涵盖了各种算法知识点和解题方法。例如,在第14训练营中,讲解了二叉树的理论基础、递归遍历、迭代遍历和统一遍历的内容。此外,在讨论中还分享了相关的博客文章和配图,帮助学员更好地理解和掌握二叉树的遍历方法。 训练营还提供了每日的讨论知识点,例如在第15的讨论中,介绍了层遍历的方法和使用队列来模拟一层一层遍历的效果。在第16的讨论中,重点讨论了如何进行调试(debug)的方法,认为掌握调试技巧可以帮助学员更好地解决问题和写出正确的算法代码。 总之,代码随想录算法训练营是一个提供优质学习和讨论环境的平台,可以帮助学员系统地学习算法知识,并提供了丰富的讨论内容和刷题建议来提高算法编程能力。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [代码随想录算法训练营每日精华](https://blog.csdn.net/weixin_38556197/article/details/128462133)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值