算法学习记录~2023.5.4~二叉树Day4~404.左叶子之和 & 513.找树左下角的值 & 112. 路径总和 & 113. 路径总和ii

前言


404.左叶子之和

题目链接

力扣题目链接

思路1:层序遍历

正常层序遍历,遍历时如果左子节点为叶子节点则是左叶子,存储即可

代码

class Solution {
public:
    int sumOfLeftLeaves(TreeNode* root) {
        queue<TreeNode*> que;
        int sum = 0;
        if ( root == NULL)
            return sum;
        que.push(root);
        while (!que.empty()){
            int size = que.size();
            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);
                //左叶子节点
                if (node -> left && node -> left ->left == NULL && node -> left -> right == NULL)
                    sum += node ->left -> val;
            }
        }
        return sum;
    }
};

思路2:递归

  1. 确定递归函数的参数和返回值
    根节点与数值之和,所以是树节点和int
  2. 确定终止条件
    如果遍历到空节点,那么左叶子值一定是0。
    此外,只有当前遍历的节点是父节点,才能判断其子节点是不是左叶子。 所以如果当前遍历的节点是叶子节点,那其左叶子也必定是0,那么终止条件为:
if (root == NULL) return 0;

//其实这个也可以不写,如果不写不影响结果,但就会让递归多进行了一层。
if (root->left == NULL && root->right== NULL) return 0; 
  1. 确定单层递归的逻辑
    当遇到左叶子节点的时候,记录数值,然后通过递归求取左子树左叶子之和,和 右子树左叶子之和,相加便是整个树的左叶子之和

代码

class Solution {
public:
    int sumOfLeftLeaves(TreeNode* root) {
        if (root == NULL) return 0;
        if (root->left == NULL && root->right== NULL) return 0;

        int leftValue = sumOfLeftLeaves(root->left);    // 左
        if (root->left && !root->left->left && !root->left->right) { // 左子树就是一个左叶子的情况
            leftValue = root->left->val;
        }
        
        int rightValue = sumOfLeftLeaves(root->right);  // 右
        
        int sum = leftValue + rightValue;               // 中

        return sum;
    }
};

总结

不能判断当前节点是否为叶子节点时,可以考虑利用他的父节点进行判断。
之前都是习惯了通过节点的左右孩子判断本节点的属性,此题打开了一定思路。


513.找树左下角的值

题目链接

力扣题目链接

思路:层序遍历

看到最后一层以及最左,直觉反应就是通过层序遍历,设一个vector存放每一层最左边的值,这样最后只需要返回最后的元素就是题目要求的数了

代码

class Solution {
public:
    int findBottomLeftValue(TreeNode* root) {
        queue<TreeNode*> que;
        que.push(root);
        int result;
        while(!que.empty()){
            result= que.front() -> val; //只需要记录每一层第一个数即可
            int size = que.size();
            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 result;   //每一层都记录且不断覆盖,则最后一个数就是最后一层的最左节点值
    }

总结

下次可以再研究下递归解法


112. 路径总和

题目链接

力扣题目链接

思路1:递归

同样是需要回溯的题目

  1. 确定递归函数的参数和返回类型
    参数:需要二叉树的根节点、一个记录到自己之前的路径和的计数器和目标总和
    返回值:因为需要找到一条符合条件的路径,不需要遍历整棵树,因此递归函数需要返回值来及时返回,bool型
bool traversal(TreeNode* cur, int count, int sum)
  1. 确定终止条件
    遍历到叶子节点时如果路径和等于目标值则true,不等于则false
if (!cur -> left && !cur -> right && count == sum)  //遍历到叶子节点且总和为目标值
            return true;
if (!cur -> left && !cur -> right && count != sum)  //遍历到叶子节点但总和不等于目标值
            return false;
  1. 确定单层递归的逻辑
    因为count只记录当前节点之前路径的和,所以应该首先将当前节点的值加进去。
    只对非空节点进行递归。
    由于递归函数是有返回值的,如果递归函数返回true,说明找到了符合要求的路径,应该立刻返回
count += cur -> val;        //每遍历到一个新的节点,就用之前节点的总和count加上现在节点的数值
if (cur -> left)
            if (traversal(cur -> left, count, sum))
                return true;
if (cur -> right)
            if (traversal(cur -> right, count, sum))
                return true;

代码

class Solution {
public:
    bool traversal(TreeNode* cur, int count, int sum){
        count += cur -> val;        //每遍历到一个新的节点,就用之前节点的总和count加上现在节点的数值
        if (!cur -> left && !cur -> right && count == sum)  //遍历到叶子节点且总和为目标值
            return true;
        if (!cur -> left && !cur -> right && count != sum)  //遍历到叶子节点但总和不等于目标值
            return false;
        if (cur -> left)
            if (traversal(cur -> left, count, sum))
                return true;
        if (cur -> right)
            if (traversal(cur -> right, count, sum))
                return true;
        return false;
    }

    bool hasPathSum(TreeNode* root, int targetSum) {
        if (root == NULL)
            return false;
        int count = 0;      //记录根节点之前的总和,因为没有所以是0
        return traversal(root, count, targetSum);
    }
};

思路2:迭代(栈)

如果使用栈来模拟递归,怎么做回溯呢?
此时栈里的一个元素不仅要记录该节点的指针,还需要记录到当前节点的路径总和
因此使用pair结构

pair<TreeNode*, int>
pair<节点指针,路径和>

代码:

class Solution {
public:
    bool hasPathSum(TreeNode* root, int targetSum) {
        if ( root == NULL )
            return false;
        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时符合于要求
            if (!node.first -> left && !node.first -> right && targetSum == node.second)
                return true;
            if (node.first -> left)
                st.push(pair<TreeNode*, int>(node.first -> left, node.second + node.first -> left -> val));
            if (node.first -> right)
                st.push(pair<TreeNode*, int>(node.first -> right, node.second + node.first -> right -> val));
        }
        return false;
    }
};

总结


113. 路径总和ii

题目链接

力扣题目链接

思路:递归

其实相当于 112. 路径总和 和 257. 二叉树的所有路径 两道题目的混合体。
主要注意在递归的时候想清楚如何回溯

代码

class Solution {
public:
    vector<vector<int>> result;     //全局变量
    vector<int> path;

    void recPath(TreeNode* cur, int count, int targetSum){  //count是该节点前所有路径总和
        count += cur -> val;
        path.push_back(cur -> val);

        if (!cur -> left && !cur -> right && count == targetSum){
            vector<int> tempPath;
            for(int i = 0; i < path.size(); i++){
                tempPath.push_back(path[i]);
            }
            result.push_back(tempPath);
        }
        if (cur -> left){
            recPath(cur -> left, count, targetSum);
            path.pop_back();        //回溯
        }
        if (cur -> right){
            recPath(cur -> right, count, targetSum);
            path.pop_back();        //回溯
        }
    }

    vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
        if (root == NULL)
            return result;
        recPath(root, 0, targetSum);
        return result;
    }
};

总结


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山药泥拌饭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值