路径总和 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 回溯算法
- 深度优先遍历:从根节点开始遍历每条路径
- 路径记录:维护当前路径的节点值
- 目标和检查:到达叶子节点时检查路径和
- 结果保存:满足条件时保存路径
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
: 每个结果的长度数组
-
核心逻辑:
- 添加当前节点值到路径
- 检查是否满足叶子节点且路径和等于目标
- 递归处理左右子树
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🌺点点关注,收藏不迷路🌺
|