代码随想录算法训练营第18天 | LeetCode513.找树左下角的值 112路径总和


513. 找树左下角的值

 本题给定一个二叉树,要求找到最底层的最左侧的节点的值。我将在这里阐述两种解题方法:1.递归法 2.迭代法(层序遍历)

1.递归法:

本题使用递归法,是要比迭代法要难的,但是也有很重要知识点在里面,回溯的思想,具体怎么个事,下面看我一步步阐述。

先分析题目,我们需要达成什么样的目标,为了完成这个目标,我们需要考虑那些问题

我们要寻找最底层,最左边的值

那么就会产生以下问题:

1.如何到达最底?

2.如何判断这个节点是整个二叉树的最底层的节点,因为 问题1 只是达到最底的节点,但仅仅只是当前子树的最底层节点,并不是当前整个二叉树的最底层节点。

3.如何到达最左的节点

要达到最底层,我们就要使用递归遍历的方法,然后我就要考虑使用哪个遍历方式(前中后序遍历),那么本题只是找到最左的节点,所以对中间节点的要求不高,我们采用哪种遍历方式都可以,我们姑且先试用前序遍历

那么如何判断这个节点是整个二叉树的最底层的节点呢?我任务需要有一个计数器cnt_node来记录一棵子树到达最底层要经过的节点数,然后再定义一个全局遍历,两个变量相比,就能得出那条路径的节点数是最多的

那么如何到达最左的节点呢?我认为这个可以当做递归的终止条件,当达到最左,并且最底层,就是递归终止之时

要递归遍历,那么就要提到我们的老朋友了,递归三部曲:

1.递归函数的参数及其返回值

        函数返回值先定义为void型,因为要有一个int型的变量来记录一条路径的节点数,所以应该有两个参数,第一个当然是TreeNode* node,还有一个就是node_cnt用来记录一条路径上的节点数

2.递归的终止条件

递归的终止条件就是当该结点是最低节点时(该节点访问左右节点都为空)

如果他是最左最低节点时,我们判断它是不是最长路径,如果是,那么改变madep的值,然后让全局变量maxdep等于最长路径的节点数,是全局变量result=该节点的值

if(node->left==NULL&&node->right==NULL){
     if(cnt_node>maxdep){
                maxdep=cnt_node;
                result=node->val;
            }
            return;
}

3.单层递归的逻辑

单层递归的逻辑,就涉及到回溯问题了

遍历一个节点下去,并且路径节点数加一,该节点遍历完,要返回到上一个节点时,就要将该路径节点数减一;

if (root->left) {   // 左
    depth++; // 深度加一
    traversal(root->left, depth);
    depth--; // 回溯,深度减一
}
if (root->right) { // 右
    depth++; // 深度加一
    traversal(root->right, depth);
    depth--; // 回溯,深度减一
}
return;

完整代码如下:

class Solution {
public:
    int maxdep=INT_MIN;
    int result;
    void getnum(TreeNode* node,int cnt_node){
        if(node->left==NULL&&node->right==NULL){
            if(cnt_node>maxdep){
                maxdep=cnt_node;
                result=node->val;
            }
            return;
        }
        if(node->left){//左
            cnt_node++;
            getnum(node->left,cnt_node);
            cnt_node--;//回溯
        }
        if(node->right){//右
            cnt_node++;
            getnum(node->right,cnt_node);
            cnt_node--;//回溯
        }
        return;
    }
    int findBottomLeftValue(TreeNode* root) {
        getnum(root,0);
        return result;
    }
};

2.迭代法:

是模板题,掌握二叉树的层序遍历即可

具体代码如下:

class Solution {
public:
    int findBottomLeftValue(TreeNode* root) {
        queue<TreeNode*>que;
        que.push(root);
        int result;
        while(!que.empty()){
            int size=que.size();
             // 这里一定要使用固定大小size,不要使用que.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;
    }
};


112. 路径总和

本题想要得到路径之和,那么就要遍历二叉树,要遍历二叉树,我们就可考虑使用递归遍历法,遇到递归,就上递归三部曲:

1.确定递归函数的参数及返回值

由于题目要确定是否存在,所以我们可以把函数返回值设置为bool型,关于参数返回值,我们先写一个TreeNode* node,这时候思考,我们如何判断该条路径上的数是否等于目标值呢,我们就需要引入一个整形来传入目标值,如果我们对路径上的值一个个相加,然后和目标值对比就会比较麻烦,不如直接传入目标值,定义为count,遍历了一个数就将count减去这个目标数,如果个数等于0时并且是到树的底部时,我们结束。

说到这,我们其实已经引出第二条了,确定递归函数的结束条件,就是上面说的:遍历了一个数就将count减去这个目标数,如果个数等于0时并且是到树的底部时,我们结束。当然如果已经到达树底了,但是count仍不为零,也是return

if(node->left==NULL&&node->right==NULL&&count==0)   return true;
if(node->left==NULL&&node->right==NULL) return false;

3.确定单层递归的逻辑:

由于这题对中间节点的要求不高,所以我们也无需考虑用哪种遍历方式,直接先后遍历左右节点就行了

当然这里有一个剪枝的操作,如果找到了合适的路径就立即返回:

if (traversal(cur->left, count)) return true;//拿左举例

事实上,本题也包含了回溯的思想,如果这条路径不合适,我们就要将count加回去

所以整体代码如下:

class Solution {
public:
    bool getpathadd(TreeNode* node,int count){
        if(node->left==NULL&&node->right==NULL&&count==0)   return true;
        if(node->left==NULL&&node->right==NULL) return false;
        if(node->left){
            count-=node->left->val;
            if(getpathadd(node->left,count)) return true;
            count+=node->left->val;
        }
        if(node->right){
            count-=node->right->val;
            if(getpathadd(node->right,count)) return true;
            count+=node->right->val;
        }
        return false;
    }
    bool hasPathSum(TreeNode* root, int targetSum) {
        if(root==nullptr)   return false;
        return getpathadd(root,targetSum-root->val);
    }
};

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值