剑指offer面试题34:二叉树中和为某一值的路径

题目描述:给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。

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

方法一:深度优先搜索
思路及算法

我们可以采用深度优先搜索的方式,枚举每一条从根节点到叶子节点的路径。当我们遍历到叶子节点,且此时路径和恰为目标和时,我们就找到了一条满足条件的路径。

解题思路:

本问题是典型的二叉树方案搜索问题,使用回溯法解决,其包含 先序遍历 + 路径记录 两部分。

先序遍历: 按照 “根、左、右” 的顺序,遍历树的所有节点。
路径记录: 在先序遍历中,记录从根节点到当前节点的路径。当路径为 ① 根节点到叶节点形成的路径 且 ② 各节点值的和等于目标值 sum 时,将此路径加入结果列表。

算法流程:
pathSum(root, sum) 函数:

1、初始化: 结果列表 res ,路径列表 path 。
2、返回值: 返回 res 即可。
recur(root, tar) 函数:

1、递推参数: 当前节点 root ,当前目标值 tar 。
2、终止条件: 若节点 root 为空,则直接返回。
3、递推工作:
       (1)路径更新: 将当前节点值 root.val 加入路径 path ;
       (2)目标值更新: tar = tar - root.val(即目标值 tar 从 sum 减至 00 );
       (3)路径记录: 当 ① root 为叶节点 且 ② 路径和等于目标值 ,则将此路径 path 加入 res 。
       (4)先序遍历: 递归左 / 右子节点。
       (5)路径恢复: 向上回溯前,需要将当前节点从路径 path 中删除,即执行 path.pop() 。

class Solution {
public:  
    vector<vector<int>> res; 
    vector<int> path;

    vector<vector<int>> pathSum(TreeNode* root, int target)
    { 
        recur(root,target);
        return res;
    }
     void recur(TreeNode* root, int target)
    {
        // 节点为null
        if(root == nullptr) return;

        path.push_back(root->val);
        target -= root->val;

        // 到达叶子节点,且符合要求
        if(target == 0 && root->left == nullptr && root->right == nullptr)
        {
            res.push_back(path);
            //path.pop_back();  // 注意需要pop, 也可以不写接下来的两行,直接往下走即可。
            //return;   
        }

        recur(root->left, target);
        recur(root->right, target);
        path.pop_back();   // 注意需要pop
    }
};
class Solution {
public:  
    vector<vector<int>> pathSum(TreeNode* root, int target)
    {
        vector<vector<int>> res; 
        vector<int> temp;
        fun(root,target,res,temp);
        return res;
    }
     void fun(TreeNode* root, int target, vector<vector<int>>& res, vector<int>& path)
    {
        // 节点为null
        if(root == nullptr) return;

        int val = root->val;
        path.push_back(val);

        // 到达叶子节点,且符合要求
        if(target == root->val && root->left == nullptr && root->right == nullptr)
        {
            res.push_back(path);
            // path.pop_back();  // 注意需要pop, 也可以不写接下来的两行,直接往下走即可。
            //return;   
        }

        fun(root->left, target - val, res, path);
        fun(root->right, target - val, res, path);
        path.pop_back();   // 注意需要pop
    }
};

 方法二:广度优先搜索
思路及算法

我们也可以采用广度优先搜索的方式,遍历这棵树。当我们遍历到叶子节点,且此时路径和恰为目标和时,我们就找到了一条满足条件的路径。

为了节省空间,我们使用哈希表记录树中的每一个节点的父节点。每次找到一个满足条件的节点,我们就从该节点出发不断向父节点迭代,即可还原出从根节点到当前节点的路径。

class Solution {
public:  
    vector<vector<int>> ret;
    unordered_map<TreeNode*, TreeNode*> parent; //关联子节点和父节点
    /*路径输出函数
     *从左右子树为空的结点开始,循环向上找父节点
     *并且将路过的结点值加入列表中
     */
    void getPath(TreeNode* node)
    {
        vector<int> tmp;
        while(node != nullptr)
        {   
            tmp.emplace_back(node->val);
            node = parent[node]; //迭代当前节点的父节点
        }
        reverse(tmp.begin(),tmp.end()); //因为从子节点向上遍历,所以调转列表顺序
        ret.emplace_back(tmp);
    }
    vector<vector<int>> pathSum(TreeNode* root, int target) 
    {
        if(root == nullptr) //判空
            return ret;
        queue<TreeNode*> q_node;    //存结点队列,从上至下层序遍历每个节点
        queue<int> q_sum;   //存路径和队列
        q_node.emplace(root);   //根节点入队
        q_sum.emplace(0);
        while(!q_node.empty()){
            TreeNode* node = q_node.front();
            q_node.pop();
            int rec = q_sum.front() + node->val;    //将广度优先搜索到的结点的值存入rec中
            q_sum.pop();
            /*
             *只有node为叶子结点且这一路结点和等于目标值
             *才运行路径输出函数
             */
            if(node->left == nullptr && node->right == nullptr)
            {
                if(rec == target)
                    getPath(node);
            }
            /*
             *否则左子树不为空
             *将左子树结点加入结点队列
             *此结点为子树结点的父节点
             *此条路径和加入路径队列中
             *右子树同理
             */
            else{
                if(node->left!=nullptr){
                    q_node.emplace(node->left);
                    parent[node->left] = node;
                    q_sum.emplace(rec);
                }
                if(node->right!=nullptr){
                    q_node.emplace(node->right);
                    parent[node->right] = node;
                    q_sum.emplace(rec);
                }
            }
        }
        return ret;
    }
};

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值