力扣第112题 路径总和 c++ 树 深度优先搜索 广度优先搜索 二叉树

题目

112. 路径总和

简单

给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false 。

叶子节点 是指没有子节点的节点。

示例 1:

输入:root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22
输出:true
解释:等于目标和的根节点到叶节点路径如上图所示。

示例 2:

输入:root = [1,2,3], targetSum = 5
输出:false
解释:树中存在两条根节点到叶子节点的路径:
(1 --> 2): 和为 3
(1 --> 3): 和为 4
不存在 sum = 5 的根节点到叶子节点的路径。

示例 3:

输入:root = [], targetSum = 0
输出:false
解释:由于树是空的,所以不存在根节点到叶子节点的路径。

提示:

  • 树中节点的数目在范围 [0, 5000] 内
  • -1000 <= Node.val <= 1000
  • -1000 <= targetSum <= 1000

思路和解题方法一 (递归)

  1. 如果当前节点 cur 是叶子节点并且 count 等于 0,表示已经找到了满足条件的路径,返回 true。
  2. 如果当前节点 cur 是叶子节点但是 count 不为 0,表示当前路径上的节点值和不等于目标值,直接返回 false。
  3. 如果当前节点有左子树,则将 count 减去左子节点的值,并递归调用 traversal 函数来继续处理左子树。
    • 如果递归调用返回 true,表示在左子树中找到了满足条件的路径,直接返回 true。
    • 如果递归调用返回 false,表示左子树中不存在满足条件的路径,回溯,将 count 加上左子节点的值,继续向右子树进行处理。
  4. 如果当前节点有右子树,则将 count 减去右子节点的值,并递归调用 traversal 函数来继续处理右子树。
    • 如果递归调用返回 true,表示在右子树中找到了满足条件的路径,直接返回 true。
    • 如果递归调用返回 false,表示右子树中不存在满足条件的路径,回溯,将 count 加上右子节点的值,继续向上层进行处理。
  5. 如果遍历完所有可能的路径后仍然没有找到满足条件的路径,返回 false。

hasPathSum 函数中,先判断根节点是否为空,如果为空直接返回 false,否则调用 traversal 函数,并将目标值减去根节点的值作为初始的 count

复杂度

        时间复杂度:

                O(n)

时间复杂度为O(n),其中n是树的节点数量。

        空间复杂度

                O(n)

空间复杂度:使用了一个递归栈来存储中间结果,对于树中的每个节点,都需要存储一次,因此空间复杂度也是O(n),其中n是树的节点数量。

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); // 调用递归函数,初始计数为给定值减去根节点的值
    }
};

c++精简代码

class Solution {
public:
    // 定义一个公共方法 hasPathSum,该方法接受两个参数:二叉树的根节点和给定的总和
    bool hasPathSum(TreeNode* root, int sum) {
        // 如果根节点为空,则返回 false,表示不存在满足条件的路径
        if (!root) return false;

        // 如果当前节点是叶子节点,并且当前节点值等于给定的总和,则返回 true,表示找到了满足条件的路径
        if (!root->left && !root->right && sum == root->val) {
            return true;
        }

        // 如果当前节点不是叶子节点,分别对其左子树和右子树调用 hasPathSum 方法
        // 递归调用时,给定的总和减去当前节点的值,因为当前节点的值已经包含在路径中
        // 并且左子树和右子树各自的路径和需要减去当前节点的值才能得到正确的路径和
        return hasPathSum(root->left, sum - root->val) || hasPathSum(root->right, sum - root->val);
    }
};

思路和解题方法二 (迭代)

  1. 首先判断根节点是否为空,如果为空,表示二叉树不存在路径,直接返回 false。

  2. 创建一个栈 st,用于存储节点指针和路径数值的 pair 对象。

  3. 将根节点和根节点的值(即路径数值)构成一个 pair,并将其压入栈中。

  4. 进入循环,只要栈不为空,就进行迭代处理。

  5. 在循环中,首先取出栈顶元素,该元素是一个节点和对应的路径数值的 pair 对象。

  6. 判断该节点是否是叶子节点,如果是叶子节点,则检查路径数值是否等于目标值 sum

    • 如果路径数值等于目标值,表示找到了满足条件的路径,直接返回 true。
    • 否则,继续弹出栈顶元素,尝试下一个元素。
  7. 如果当前节点不是叶子节点,依次检查它的左右子节点是否为空。

    • 如果右子节点非空,则将右子节点和路径数值加上右子节点的值作为新的 pair 对象,压入栈中。
    • 如果左子节点非空,则将左子节点和路径数值加上左子节点的值作为新的 pair 对象,压入栈中。 这样可以实现按照左子节点优先的顺序进行迭代处理。
  8. 当遍历完所有可能的路径后仍然没有找到满足条件的路径,则返回 false。

复杂度

        时间复杂度:

                O(n)

时间复杂度为O(n),其中n是二叉树中节点的数量。

        空间复杂度

                O(n)

空间复杂度为O(n),需要使用一个栈来存储节点。

c++ 代码

class solution {
    // 定义一个用于存储节点指针和路径和的pair类型栈
public:
    bool haspathsum(TreeNode* root, int sum) {
        // 如果根节点为空,则返回false,表示没有路径满足和为sum
        if (root == null) return false;
        
        // 初始化一个空的栈,用于存储节点指针和路径和的pair
        // 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));
            }
        }
        
        // 如果循环结束还没有找到满足条件的路径,返回false
        return false;
    }
};

觉得有用的话可以点点赞,支持一下。

如果愿意的话关注一下。会对你有更多的帮助。

每天都会不定时更新哦  >人<  。

posted @   lenyan~  阅读(20)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示