二叉树的所有路径:深度优先搜索详解

VibeCoding·九月创作之星挑战赛 10w+人浏览 1.5k人参与


🌺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. 问题分析

我们需要遍历二叉树的所有路径,关键点在于:

  1. 如何确定到达叶子节点?
  2. 如何记录和构建路径字符串?
  3. 如何管理内存分配和释放?

3. 算法思路

采用深度优先搜索(DFS)递归遍历二叉树:

  1. 从根节点开始遍历
  2. 遇到叶子节点时,将当前路径加入结果集
  3. 非叶子节点继续递归遍历其子节点
  4. 使用动态数组存储路径字符串

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. 代码解释

  1. dfs函数

    • 将当前节点值转为字符串
    • 构建新路径(处理空路径和已有路径两种情况)
    • 到达叶子节点时将路径加入结果集
    • 非叶子节点继续递归遍历
    • 动态管理内存分配和释放
  2. 主函数binaryTreePaths

    • 初始化结果数组和容量
    • 调用DFS函数进行遍历
    • 返回结果数组
  3. 内存管理

    • 动态扩容结果数组
    • 及时释放临时字符串内存
    • 结果字符串由调用者负责释放

6. 复杂度分析

  • 时间复杂度:O(n),每个节点访问一次
  • 空间复杂度:O(n),递归栈空间和路径存储空间

7. 示例验证

以示例1 root = [1,2,3,null,5] 为例:

  1. 从根节点1开始
  2. 遍历左子树2:
    • 构建路径"1->2"
    • 遍历右子树5:
      • 构建路径"1->2->5"(叶子节点,加入结果)
  3. 遍历右子树3:
    • 构建路径"1->3"(叶子节点,加入结果)
  4. 最终结果:[“1->2->5”, “1->3”]

8. 总结

本题展示了DFS在二叉树遍历中的典型应用,需要注意:

  1. 路径构建的字符串处理
  2. 内存的动态分配和释放
  3. 叶子节点的判断条件

关键点

  • 使用递归实现简洁的DFS
  • 正确处理路径字符串的拼接
  • 动态数组管理结果集

这种解法清晰直观,适合面试场景,也体现了二叉树遍历的基本思想。

在这里插入图片描述


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Seal^_^

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

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

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

打赏作者

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

抵扣说明:

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

余额充值