🌺The Begin🌺点点关注,收藏不迷路🌺
|
1. 题目描述
给定一个二叉树的根节点 root
,要求返回所有从根节点到叶子节点的路径,路径以字符串形式表示,节点之间用 "->"
连接。
示例 1:
输入:root = [1,2,3,null,5]
输出:["1->2->5","1->3"]
解释:有两条路径:1→2→5 和 1→3
示例 2:
输入:root = [1]
输出:["1"]
解释:只有根节点自身构成一条路径
2. 问题分析
我们需要遍历二叉树的所有路径,关键点在于:
- 如何确定到达叶子节点?
- 如何记录和构建路径字符串?
- 如何管理内存分配和释放?
3. 算法思路
采用深度优先搜索(DFS)递归遍历二叉树:
- 从根节点开始遍历
- 遇到叶子节点时,将当前路径加入结果集
- 非叶子节点继续递归遍历其子节点
- 使用动态数组存储路径字符串
4. 代码实现
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
void dfs(struct TreeNode* root, char* path, char*** result, int* returnSize, int* capacity) {
if (!root) return;
// 计算当前节点值的字符串长度
int len = snprintf(NULL, 0, "%d", root->val);
char* valStr = (char*)malloc(len + 1);
sprintf(valStr, "%d", root->val);
// 构建新路径
char* newPath;
if (strlen(path) == 0) {
newPath = valStr;
} else {
int newLen = strlen(path) + 2 + len + 1; // "->" + val + '\0'
newPath = (char*)malloc(newLen);
sprintf(newPath, "%s->%s", path, valStr);
free(valStr);
}
// 如果是叶子节点,将路径加入结果
if (!root->left && !root->right) {
// 检查是否需要扩容
if (*returnSize >= *capacity) {
*capacity *= 2;
*result = (char**)realloc(*result, *capacity * sizeof(char*));
}
(*result)[(*returnSize)++] = newPath;
} else {
// 继续遍历左右子树
dfs(root->left, newPath, result, returnSize, capacity);
dfs(root->right, newPath, result, returnSize, capacity);
free(newPath);
}
}
char** binaryTreePaths(struct TreeNode* root, int* returnSize) {
*returnSize = 0;
if (!root) return NULL;
int capacity = 16; // 初始容量
char** result = (char**)malloc(capacity * sizeof(char*));
dfs(root, "", &result, returnSize, &capacity);
return result;
}
5. 代码解释
-
dfs函数:
- 将当前节点值转为字符串
- 构建新路径(处理空路径和已有路径两种情况)
- 到达叶子节点时将路径加入结果集
- 非叶子节点继续递归遍历
- 动态管理内存分配和释放
-
主函数binaryTreePaths:
- 初始化结果数组和容量
- 调用DFS函数进行遍历
- 返回结果数组
-
内存管理:
- 动态扩容结果数组
- 及时释放临时字符串内存
- 结果字符串由调用者负责释放
6. 复杂度分析
- 时间复杂度:O(n),每个节点访问一次
- 空间复杂度:O(n),递归栈空间和路径存储空间
7. 示例验证
以示例1 root = [1,2,3,null,5]
为例:
- 从根节点1开始
- 遍历左子树2:
- 构建路径"1->2"
- 遍历右子树5:
- 构建路径"1->2->5"(叶子节点,加入结果)
- 遍历右子树3:
- 构建路径"1->3"(叶子节点,加入结果)
- 最终结果:[“1->2->5”, “1->3”]
8. 总结
本题展示了DFS在二叉树遍历中的典型应用,需要注意:
- 路径构建的字符串处理
- 内存的动态分配和释放
- 叶子节点的判断条件
关键点:
- 使用递归实现简洁的DFS
- 正确处理路径字符串的拼接
- 动态数组管理结果集
这种解法清晰直观,适合面试场景,也体现了二叉树遍历的基本思想。
🌺The End🌺点点关注,收藏不迷路🌺
|