路径总和(1和2)

做这道题之前首先提到一点,那就是递归什么时候需要返回值,什么时候不需要返回值,可以分为三类:

  1. 要遍历整颗二叉树,同时不需要处理返回值,递归函数就不需要返回值(路径总和2)

  1. 需要搜索整棵二叉树,同时还需要处理递归返回值,则递归函数就需要返回值(二叉树的最近公共祖先)

  1. 只需要遍历部分二叉树,则递归一定需要返回值,因为遇到了符合条件的就要及时返回(路径总和1)

路径总和1

思路:

  1. 确定递归函数参数和返回值:注意,这个时候要求返回true or false,则用bool定义函数。

同时因为不需要遍历整棵二叉树,则需要int返回值。

bool traversal(treenode* cur, int count)   // 注意函数的返回类型
  1. 确定终止条件:

和左叶子之和类似(可见我相关文章),这道题还是要使用叶子节点,我们还是老规矩,考虑叶子节点的父节点入手,父节点的左右节点为空,意味着找到了叶子节点。但是同时我们还需要根据题目的要求,找到满足sum的值:

首先计数器如何统计这一条路径的和呢?

不要去累加然后判断是否等于目标和,那么代码比较麻烦,可以用递减,让计数器count初始为目标和,然后每次减去遍历路径节点上的数值。

如果最后count == 0,同时到了叶子节点的话,说明找到了目标和。

如果遍历到了叶子节点,count不为0,就是没找到。

if (!cur->left && !cur->right && count == 0) return true; // 遇到叶子节点,并且计数为0
if (!cur->left && !cur->right) return false; // 遇到叶子节点而没有找到合适的边,直接返回
  1. 确定单层递归逻辑:

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;

整体代码如下:

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);
    }
};

这里注意一下,可以把回溯放到代码中的,那就是从count入手,

回溯隐藏在traversal(cur->left, count - cur->left->val)这里, 因为把count - cur->left->val 直接作为参数传进去,函数结束,count的数值没有改变。

迭代:

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;
    }
};

路径总和2:

https://leetcode.cn/problems/path-sum-ii/

给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径。

说明: 叶子节点是指没有子节点的节点。

示例: 给定如下二叉树,以及目标和 sum = 22,

class Solution {
private:
    vector<vector<int>> result;
    vector<int> path;
public:
    vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
        if(root == NULL) return result;
        path.push_back(root -> val);
        traversal(root,targetSum - root -> val);
        return result;

    }
    void traversal(TreeNode* cur, int count){
    if(cur -> left == NULL && cur -> right == NULL && count == 0){
        result.push_back(path);
    }
    if(cur -> left == NULL && cur -> right == NULL) return;
    if(cur -> left){
        path.push_back(cur -> left -> val);
        count -= cur -> left -> val;
        traversal(cur -> left, count);
        count += cur -> left -> val;
        path.pop_back();
    }
    if(cur -> right){
        path.push_back(cur -> right -> val);
        count -= cur -> right -> val;
        traversal(cur -> right, count);
        count += cur -> right -> val;
        path.pop_back();
    }
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值