剑指Offer:[第15天 搜索与回溯算法(中等)]--->二叉树中和为某一值的路径


一、题目描述

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

示例1:
在这里插入图片描述

输入:root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
输出:[[5,4,11,2],[5,8,4,5]]

示例2:
在这里插入图片描述

输入:root = [1,2,3], targetSum = 5
输出:[]

示例3:

输入:root = [1,2], targetSum = 0
输出:[]

提示:

①树中节点总数在范围 [0, 5000] 内
②-1000 <= Node.val <= 1000
③-1000 <= targetSum <= 1000


二、思路分析

注:思路分析中的一些内容和图片参考自力扣各位前辈的题解,感谢他们的无私奉献

思路

本问题是典型的二叉树方案搜索问题,使用回溯法解决,其包含 先序遍历 + 路径记录 两部分。
先序遍历:按照 “根、左、右” 的顺序,遍历树的所有节点。
路径记录:在先序遍历中,记录从根节点到当前节点的路径。当路径为根节点到叶节点形成的路径且各节点值的和等于目标值 sum 时,将此路径加入结果列表。
在这里插入图片描述
算法流程:
①pathSum函数:
初始化:为结果列表res,路径列表path和记录每行元素个数的列表returnColusmSize分配空间
运行:从根结点开始执行recur函数
返回值:返回res
②recur函数:
判断当前节点是否为空,如果为空则直接返回
将当前节点的值记录到path中,并将target减去当前节点值
判断当前节点是否为叶节点、target是否为0
----如果是,则为res的当前行分配空间、将路径记录到res当前行、行数+1
----如果不是,则递归处理左右孩子
进行回溯
案例分析:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
复杂度分析:
时间复杂度 O ( N ) \rm{O(N)} O(N)N为二叉树的节点数,先序遍历需要遍历所有节点
空间复杂度 O ( N ) \rm{O(N)} O(N):最差情况下,即树退化为链表时,path存储所有树节点,使用O(N)额外空间。


三、整体代码

整体代码如下

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */

/**
 * Return an array of arrays of size *returnSize.
 * The sizes of the arrays are returned as *returnColumnSizes array.
 * Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
 */

void recur(struct TreeNode* root, int target, int* returnSize, int** returnColumnSizes, int nums, int* path, int** res){
    //如果当前节点为空,则直接返回
    if(!root){
        return;
    }
    path[nums++] = root->val; //将当前节点值记录到path中
    target -= root->val;      //将target减去当前节点值
    //如果target等于0且当前节点为叶节点,记录此条路径
    if(!root->left && !root->right && target == 0){
        res[*returnSize] = (int*)malloc(sizeof(int) * nums);
        (*returnColumnSizes)[*returnSize] = nums;
        for(int i = 0; i < nums; i++){
            res[*returnSize][i] = path[i];  //记录路径
        }
        (*returnSize)++;  //行数++
    }
    else{
        //递归处理左右孩子
        recur(root->left, target, returnSize, returnColumnSizes, nums, path, res);
        recur(root->right, target, returnSize, returnColumnSizes, nums, path, res);
    }
    nums--; //回溯
} 

int** pathSum(struct TreeNode* root, int target, int* returnSize, int** returnColumnSizes){
    *returnSize = 0;  //初始化行数
    //为记录每一行元素个数的returnColumnSizes、路径path、返回的结果res分配内存空间
    *returnColumnSizes = (int*)malloc(sizeof(int)*1001);
    int* path = (int*)malloc(sizeof(int)*1001);
    int** res = (int*)malloc(sizeof(int*)*1001);
    int nums = 0;   //初始化nums为0,用于记录当前路径有多少个节点
    recur(root, target, returnSize, returnColumnSizes, nums, path, res); //从根结点开始进行处理
    return res;
}

运行,测试通过
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

知初与修一

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

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

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

打赏作者

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

抵扣说明:

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

余额充值