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

513. 找树左下角的值

文章链接:代码随想录 (programmercarl.com)

视频链接:怎么找二叉树的左下角? 递归中又带回溯了,怎么办?| LeetCode:513.找二叉树左下角的值_哔哩哔哩_bilibili

 笔记

  • 层序遍历基本掌握
  • 递归:没想到是个深度问题

C++代码

层序遍历

class Solution {
public:
    int findBottomLeftValue(TreeNode* root) {
        queue<TreeNode*> que;
        int res;
        if(root==nullptr)return 0;
        que.push(root);
        while(!que.empty()){
            int size=que.size();
            res=que.front()->val;
            for(int i=0;i<size;i++){
                TreeNode* node=que.front();
                que.pop();
                if(node->left)que.push(node->left);
                if(node->right)que.push(node->right);
            }
        }
        return res;
    }
};

递归


class Solution {
public:
    int MaxDepth=INT_MIN;
    int res;
    void findLeft(TreeNode* root,int depth){
        if(root->left==nullptr && root->right==nullptr){
            if(MaxDepth<depth){
                res=root->val;
                MaxDepth=depth;
            }
        }
        if(root->left){
            findLeft(root->left,depth+1);
        }
        if(root->right){
            findLeft(root->right,depth+1);
        }
    }

    int findBottomLeftValue(TreeNode* root) {
        findLeft(root,1);
        return res;

    }
};

112. 路径总和

文章链接:代码随想录 (programmercarl.com)

视频链接:拿不准的遍历顺序,搞不清的回溯过程,我太难了! | LeetCode:112. 路径总和_哔哩哔哩_bilibili

笔记 

  • 递归:
    • 终止条件:1.不要去累加然后判断是否等于目标和,那么代码比较麻烦,可以用递减,让计数器count初始为目标和,然后每次减去遍历路径节点上的数值。2.遇到叶子节点直接返回false
    • 中节点没有处理逻辑
    • 递归函数什么时候需要返回值?什么时候不需要返回值?这里总结如下三点:

      • 如果需要搜索整棵二叉树且不用处理递归返回值,递归函数就不要返回值

      • 如果需要搜索整棵二叉树且需要处理递归返回值,递归函数就需要返回值。 
      • 如果要搜索其中一条符合条件的路径,那么递归一定需要返回值,因为遇到符合条件的路径了就要及时返回。(本题的情况)
  • 迭代
    • 用pair来存储路径数值
    • 每次入栈的数值都加上了经过的路径上的数

C++代码 

递归

class Solution {
private:
    bool traversal(TreeNode* cur, int count) {
        if (!cur->left && !cur->right && count == 0) return true; // 遇到叶子节点,并且计数为0
        if (!cur->left && !cur->right) return false; // 遇到叶子节点直接返回

        if (cur->left) { // 左
            count -= cur->left->val; // 递归,处理节点;
            if (traversal(cur->left, count)) return true;
            count += cur->left->val; // 回溯,撤销处理结果
        }
        if (cur->right) { // 右
            count -= cur->right->val; // 递归,处理节点;
            if (traversal(cur->right, count)) return true;
            count += cur->right->val; // 回溯,撤销处理结果
        }
        return false;
    }

public:
    bool hasPathSum(TreeNode* root, int sum) {
        if (root == NULL) return false;
        return traversal(root, sum - root->val);
    }
};

迭代

class solution {

public:
    bool haspathsum(TreeNode* root, int sum) {
        if (root == null) return false;
        // 此时栈里要放的是pair<节点指针,路径数值>
        stack<pair<TreeNode*, int>> st;
        st.push(pair<TreeNode*, int>(root, root->val));
        while (!st.empty()) {
            pair<TreeNode*, int> node = st.top();
            st.pop();
            // 如果该节点是叶子节点了,同时该节点的路径数值等于sum,那么就返回true
            if (!node.first->left && !node.first->right && sum == node.second) return true;

            // 右节点,压进去一个节点的时候,将该节点的路径数值也记录下来
            if (node.first->right) {
                st.push(pair<TreeNode*, int>(node.first->right, node.second + node.first->right->val));
            }

            // 左节点,压进去一个节点的时候,将该节点的路径数值也记录下来
            if (node.first->left) {
                st.push(pair<TreeNode*, int>(node.first->left, node.second + node.first->left->val));
            }
        }
        return false;
    }
};

 

113. 路径总和 II

文章链接:代码随想录 (programmercarl.com)

 视频链接:拿不准的遍历顺序,搞不清的回溯过程,我太难了! | LeetCode:112. 路径总和_哔哩哔哩_bilibili

笔记

  • 返回值是二维数组,实际上在计算结果的时候需要一维数组的辅助
  • 递归大体上跟112一样,但是要注意path也要回溯

C++代码

class Solution {
public:
    vector<vector<int>>res;
    vector<int>path;
    void getPath(TreeNode* root,int count){
        if(!root->left && !root->right && count==0){
            res.push_back(path);
            return;
        }
        if(!root->left && !root->right)return ;
        if(root->left){
            path.push_back(root->left->val);
            getPath(root->left,count-root->left->val);
            path.pop_back();
        }
        if(root->right){
            path.push_back(root->right->val);
            getPath(root->right,count-root->right->val);
            path.pop_back();//回溯
        }
        return;
        
    }
    vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
        res.clear();
        path.clear();

        if(!root)return res;
        path.push_back(root->val);
        getPath(root,targetSum-root->val);//-root->val
        return res;
    }
};

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

文章链接:代码随想录 (programmercarl.com)

视频链接:坑很多!来看看你掉过几次坑 | LeetCode:106.从中序与后序遍历序列构造二叉树_哔哩哔哩_bilibili

 笔记

  • 通过切割区间返回节点来计算
  • 先切割中序再切割后序
  • 切割区间左闭右开,全部都要遵循这个规则
  • 递归处理左右区间
  • 中序后序的数组长度是一致的

C++代码

class Solution {
private:
    // 中序区间:[inorderBegin, inorderEnd),后序区间[postorderBegin, postorderEnd)
    TreeNode* traversal (vector<int>& inorder, int inorderBegin, int inorderEnd, vector<int>& postorder, int postorderBegin, int postorderEnd) {
        if (postorderBegin == postorderEnd) return NULL;

        int rootValue = postorder[postorderEnd - 1];
        TreeNode* root = new TreeNode(rootValue);

        if (postorderEnd - postorderBegin == 1) return root;

        int delimiterIndex;
        for (delimiterIndex = inorderBegin; delimiterIndex < inorderEnd; delimiterIndex++) {
            if (inorder[delimiterIndex] == rootValue) break;
        }
        // 切割中序数组
        // 左中序区间,左闭右开[leftInorderBegin, leftInorderEnd)
        int leftInorderBegin = inorderBegin;
        int leftInorderEnd = delimiterIndex;
        // 右中序区间,左闭右开[rightInorderBegin, rightInorderEnd)
        int rightInorderBegin = delimiterIndex + 1;
        int rightInorderEnd = inorderEnd;

        // 切割后序数组
        // 左后序区间,左闭右开[leftPostorderBegin, leftPostorderEnd)
        int leftPostorderBegin =  postorderBegin;
        int leftPostorderEnd = postorderBegin + delimiterIndex - inorderBegin; // 终止位置是 需要加上 中序区间的大小size
        // 右后序区间,左闭右开[rightPostorderBegin, rightPostorderEnd)
        int rightPostorderBegin = postorderBegin + (delimiterIndex - inorderBegin);
        int rightPostorderEnd = postorderEnd - 1; // 排除最后一个元素,已经作为节点了

        root->left = traversal(inorder, leftInorderBegin, leftInorderEnd,  postorder, leftPostorderBegin, leftPostorderEnd);
        root->right = traversal(inorder, rightInorderBegin, rightInorderEnd, postorder, rightPostorderBegin, rightPostorderEnd);

        return root;
    }
public:
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        if (inorder.size() == 0 || postorder.size() == 0) return NULL;
        // 左闭右开的原则
        return traversal(inorder, 0, inorder.size(), postorder, 0, postorder.size());
    }
};

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

 文章链接:代码随想录 (programmercarl.com)

 笔记

  • 新建节点
  • 中序去除根结点
  • 前序大小与中序相等

C++代码

class Solution {
public:
    TreeNode* traversal(vector<int>& preorder,int preBegin,int preEnd,vector<int>& inorder,int inBegin,int inEnd){
        if(preBegin==preEnd)return NULL;

        int rootValue=preorder[preBegin];
        TreeNode* root=new TreeNode(rootValue);//新建树节点

        if(preEnd-preBegin==1)return root;

        int demIndex;
        for(demIndex=inBegin;demIndex<inEnd;demIndex++){
            if(inorder[demIndex]==rootValue)break;
        }
        int leftInorderBegin=inBegin;
        int leftInorderEnd=demIndex;

        int rightInorderBegin=demIndex+1;//去除root
        int rightInorderEnd=inEnd;
        // 两个数组大小相等
        int leftPreOrderBegin=preBegin+1;
        int leftPreOrderEnd=preBegin+demIndex-inBegin+1;

        int rightPreOrderBegin=preBegin+(demIndex-inBegin)+1;
        int rightPreOrderEnd=preEnd;

        root->left=traversal(preorder,leftPreOrderBegin,leftPreOrderEnd,inorder,leftInorderBegin,leftInorderEnd);
        root->right=traversal(preorder,rightPreOrderBegin,rightPreOrderEnd,inorder,rightInorderBegin,rightInorderEnd);
        return root;
    }
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        if(inorder.size()==0 || preorder.size()==0)return NULL;
        return traversal(preorder,0,preorder.size(),inorder,0,inorder.size());
    }
};

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 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、付费专栏及课程。

余额充值