LeetCode习题 ——路径总和(1,2,3)

1.路径总和 (1)

Given the root of a binary tree and an integer targetSum, return true if the tree has a root-to-leaf path such that adding up all the values along the path equals targetSum.

leaf is a node with no children.

Example 1:

Input: root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22
Output: true
Explanation: The root-to-leaf path with the target sum is shown.

Example 2:

Input: root = [1,2,3], targetSum = 5
Output: false
Explanation: There two root-to-leaf paths in the tree:
(1 --> 2): The sum is 3.
(1 --> 3): The sum is 4.
There is no root-to-leaf path with sum = 5.

Example 3:

Input: root = [], targetSum = 0
Output: false
Explanation: Since the tree is empty, there are no root-to-leaf paths.

Constraints:

  • The number of nodes in the tree is in the range [0, 5000].
  • -1000 <= Node.val <= 1000
  • -1000 <= targetSum <= 1000

以上是路径总和(1)的题目,

题目大致的意思是在一颗二叉树中寻找一个路径,使得经过的二叉树节点之和为给定数值。如果能够找到这样的路径,就返回true,如果不能找到,那就返回false。

思路:

        首先明确一点,就是这棵树必须得全部遍历了,其次,这棵树的遍历是需要从根节点走到叶子节点的,这一条路径的总和须满足给定数值(有两种方法累积节点,一个是加,一个是减,本思路采用减法进行数值累积)。

        遍历这棵树,我这边采用的方式是递归的方式。

  1. 先确定递归出口,明确,当前节点为空时,就返回false。
  2. 后考虑判断条件,因为这个路径的最终是要走到叶子节点的, 所以,我们需要考虑一下叶子节点的判断条件,以及是否满足总和为给定数值的条件。     
  3. 遍历当前节点的左右子树。                 

 确立好了解题思路后,我们就可以明确代码了,代码较为简单

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
// 上注释为,树节点的定义。
class Solution {
public:
    bool hasPathSum(TreeNode* root, int targetSum) {
        if (root == nullptr) return false; // 递归出口
        if (root->left == nullptr && root->right == nullptr) return targetSum == root->val;
        // 判断是否是叶子节点,同时返回的结果代表当前是否与给定数值相符合。
        return hasPathSum(root->left,targetSum-root->val) || hasPathSum(root->right,targetSum-root->val);
        // 只要左右节点的递归遍历有一个满足就行啦,所以用 || 连接逻辑判断
        }
};

2. 路径总和 (2)

Given the root of a binary tree and an integer targetSum, return all root-to-leaf paths where the sum of the node values in the path equals targetSum. Each path should be returned as a list of the node values, not node references.

root-to-leaf path is a path starting from the root and ending at any leaf node. A leaf is a node with no children.

Example 1:

Input: root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
Output: [[5,4,11,2],[5,8,4,5]]
Explanation: There are two paths whose sum equals targetSum:
5 + 4 + 11 + 2 = 22
5 + 8 + 4 + 5 = 22

Example 2:

Input: root = [1,2,3], targetSum = 5
Output: []

Example 3:

Input: root = [1,2], targetSum = 0
Output: []

Constraints:

  • The number of nodes in the tree is in the range [0, 5000].
  • -1000 <= Node.val <= 1000
  • -1000 <= targetSum <= 1000

由于这是一个系列的题型,所以题目意思会稍显相近,本题的难点在于,题目要求返回一个二维的vector,同时vector里面记录了满足条件的节点,每一个一维的vector 代表一条符合条件的路径之和,这里面就牵涉到了递归的回溯问题,我们是否需要选择这个当前元素,代码稍长一些,但是需要保证逻辑清晰。

思路 :

        因为题目要求返回一个二维vector,所以我们不能在原函数里面递归,因为我这边不知道怎么去在函数里面递归处理,所以,我新建立了一个函数,用它将我们需要的vector跑好,最后再由原函数返回即可。

        首先思考一下题目,很显然,我们需要有回溯,同时,我们还要遍历全部的节点。

        所以,我们先可以进行树的遍历,

        既然开始遍历,那么还是三步走,递归出口,判断条件,结果返回。

  1. 递归出口
    1. 当前节点为nullptr的时候,肯定是要返回的。
    2. 当前节点为叶子节点,同时满足路径总和为所给定的数值,即可将当前一维vector传入二维vector,说明已经找到一条符合条件的路径了,就可以返回了。
    3. 若当前节点为叶子节点,同时不满足条件时,那就算啦,他都不满足条件了,肯定是不能放在二维的vector里面的,返回就行。
  2. 判断条件  
    1. 如果左子树不为空,那么我们可以先行记录下来,将当前节点的左儿子数值丢到一维的vector里面,反正咱要回溯的,所以先丢为敬,同时,目标数值减去当前节点的左儿子数值。并开始当前节点的左儿子的遍历。之后回溯就好,抹除不符合条件的遍历。
    2. 如果右子树不为空,与上同理。
  3. 结果返回
    1. ​​​​​​​直接返回返回 return; 就好了,前面的递归已经将vector数组全部处理好了,这个函数的功能就完全实现了,后面的结果就不需要返回太多。

代码稍显混乱,但是其中逻辑需要好好明确。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    vector<vector<int>> result;
    vector<int> path;

    void traversal(TreeNode* root,int sum) {
        if (root == nullptr) return ;
        if (root->left == nullptr && root->right == nullptr && sum == 0){
            result.push_back(path);
            return ;
        }
        if (root->left == nullptr && root->right == nullptr){
            return ;
        }
        if (root->left != nullptr){
            path.push_back(root->left->val);
            sum -= root->left->val;
            traversal(root->left,sum);
            sum += root->left->val;
            path.pop_back();
        }
        if (root->right != nullptr){
            path.push_back(root->right->val);
            sum -= root->right->val;
            traversal(root->right,sum);
            sum += root->right->val;
            path.pop_back();
        }

        return ;
     }

    vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
        result.clear();
        path.clear();
        if (root == nullptr) return result;
        path.push_back(root->val);
        traversal(root,targetSum-root->val);
        return result;
    }
};

 

3. 路径总和(3)

Given the root of a binary tree and an integer targetSum, return the number of paths where the sum of the values along the path equals targetSum.

The path does not need to start or end at the root or a leaf, but it must go downwards (i.e., traveling only from parent nodes to child nodes).

Example 1:

Input: root = [10,5,-3,3,2,null,11,3,-2,null,1], targetSum = 8
Output: 3
Explanation: The paths that sum to 8 are shown.

Example 2:

Input: root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
Output: 3

Constraints:

  • The number of nodes in the tree is in the range [0, 1000].
  • -109 <= Node.val <= 109
  • -1000 <= targetSum <= 1000

 上为题目,这个路径总和(3)就有意思啦,怎么说?这个首先是去掉一定要从根节点走到叶子节点的限制

要求,从任意一个节点出发,只要满足给定数值,就行,非常的野,这种题目有意思就好好想想

思路:

  1. 首先,他必须遍历完所有节点,因为我只要从任意一个节点开始的路径,符合条件就好
  2. 确定从当前节点开始遍历。 
  3. 特别划重点注意:如果当前节点凑够了目标数值,并不需要直接返回,因为本题会出现负数节点,若叶子节点走出的路径出现更长的一条满足,那么那一条也是可以的。

 显然,我们可以确定,需要有一个主遍历,即遍历整棵树的遍历,他用于统计总和路径,并返回总和答案

 其次,我们需要一个副遍历,就是从当前节点开始的遍历,我们需要记录从当前节点遍历开始,有多少条路   径符合答案结果,这个的返回值时当前节点开始,满足条件的路径数量。

于是我们的代码就比较清晰了,这个思路是可以的。

class Solution {
public:

    int work(TreeNode* root,long targetSum) {
        if (root == nullptr) return 0;

        int ret = 0;
        if (root->val == targetSum) ret++; // 这里面非常重要
        
        ret +=  work(root->left,targetSum - root->val);
        ret +=  work(root->right,targetSum - root->val);
        return ret;
    }

    int pathSum(TreeNode* root, int targetSum) {
        if (root == nullptr) return 0;     
        int ret = work(root,targetSum);
        ret += pathSum(root->left,targetSum);
        ret += pathSum(root->right,targetSum);
        return ret;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值