路径总和 II:回溯算法在二叉树中的应用

路径总和 II:回溯算法在二叉树中的应用

    • 1. 问题描述
    • 2. 解题思路
      • 2.1 回溯算法
      • 2.2 关键点
    • 3. 代码实现
    • 4. 代码解析
      • 4.1 回溯函数
      • 4.2 主函数
    • 5. 复杂度分析
    • 6. 测试用例
    • 7. 关键点总结
    • 8. 扩展思考


🌺The Begin🌺点点关注,收藏不迷路🌺

1. 问题描述

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

示例1

输入: 
    5
   / \
  4   8
 /   / \
11  13  4
/  \    / \
7    2 5   1
targetSum = 22

输出: [[5,4,11,2],[5,8,4,5]]

示例2

输入: 
    1
   / \
  2   3
targetSum = 5
输出: []

2. 解题思路

2.1 回溯算法

  1. 深度优先遍历:从根节点开始遍历每条路径
  2. 路径记录:维护当前路径的节点值
  3. 目标和检查:到达叶子节点时检查路径和
  4. 结果保存:满足条件时保存路径

2.2 关键点

  • 叶子节点判断(左右子节点均为空)
  • 路径回溯(添加和移除当前节点)
  • 动态内存管理

3. 代码实现

#include <stdlib.h>

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

void backtrack(struct TreeNode* root, int targetSum, int* path, int pathSize, 
               int*** result, int* returnSize, int** returnColumnSizes) {
    if (root == NULL) return;
    
    // 添加当前节点到路径
    path[pathSize] = root->val;
    pathSize++;
    
    // 检查是否是叶子节点且路径和等于目标
    if (root->left == NULL && root->right == NULL && root->val == targetSum) {
        // 分配空间保存当前路径
        (*result)[*returnSize] = (int*)malloc(pathSize * sizeof(int));
        memcpy((*result)[*returnSize], path, pathSize * sizeof(int));
        (*returnColumnSizes)[*returnSize] = pathSize;
        (*returnSize)++;
        return;
    }
    
    // 递归处理左右子树
    backtrack(root->left, targetSum - root->val, path, pathSize, result, returnSize, returnColumnSizes);
    backtrack(root->right, targetSum - root->val, path, pathSize, result, returnSize, returnColumnSizes);
}

int** pathSum(struct TreeNode* root, int targetSum, int* returnSize, int** returnColumnSizes) {
    // 初始化返回结构
    *returnSize = 0;
    int** result = (int**)malloc(1000 * sizeof(int*));
    *returnColumnSizes = (int*)malloc(1000 * sizeof(int));
    int* path = (int*)malloc(1000 * sizeof(int));
    
    backtrack(root, targetSum, path, 0, &result, returnSize, returnColumnSizes);
    
    free(path);
    return result;
}

4. 代码解析

4.1 回溯函数

  • 参数说明

    • root: 当前节点
    • targetSum: 剩余目标和
    • path: 当前路径数组
    • pathSize: 当前路径长度
    • result: 结果数组
    • returnSize: 结果数量
    • returnColumnSizes: 每个结果的长度数组
  • 核心逻辑

    1. 添加当前节点值到路径
    2. 检查是否满足叶子节点且路径和等于目标
    3. 递归处理左右子树

4.2 主函数

  • 初始化结果存储空间
  • 调用回溯函数
  • 释放临时路径内存

5. 复杂度分析

  • 时间复杂度:O(n²),每个节点访问一次,最坏情况下需要保存所有路径
  • 空间复杂度:O(n),递归栈深度和路径存储

6. 测试用例

测试用例1

// 输入:
//       5
//      / \
//     4   8
//    /   / \
//   11  13  4
//  /  \    / \
// 7    2 5   1
// targetSum = 22
// 预期输出: [[5,4,11,2],[5,8,4,5]]

测试用例2

// 输入:
//    1
//   / \
//  2   3
// targetSum = 5
// 预期输出: []

测试用例3

// 输入:
//    1
//   /
//  2
// targetSum = 0
// 预期输出: []

7. 关键点总结

回溯框架:经典的选择-递归-回溯结构
叶子节点判断:左右子节点均为空
路径和计算:递减目标和避免重复计算
内存管理:合理分配和释放动态数组

8. 扩展思考

  • 如何优化内存使用效率?
  • 如何实现迭代解法?
  • 如何扩展到非二叉树的情况?

📌 总结:路径总和II问题展示了回溯算法在树结构中的典型应用,通过深度优先遍历和路径记录,可以高效找出所有满足条件的路径。掌握这种方法对解决类似路径搜索问题很有帮助!

在这里插入图片描述


🌺The End🌺点点关注,收藏不迷路🌺
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Seal^_^

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

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

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

打赏作者

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

抵扣说明:

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

余额充值