【4.7】图搜索算法-DFS和BFS解根到叶子节点数字之和

一、题目

给定一个二叉树,它的每个结点都存放一个 0-9 的数字, 每条从根到叶子节点的路径都代表一个数字 。
例如,从根到叶子节点路径 1->2->3 代表数字 123。计算从根到叶子节点生成的所有数字之和。
说明 : 叶子节点是指没有子节点的节点。
示例 1:
输入 : [ 1 , 2 , 3 ]
1
/ \
2 3
输出 : 25
解释 :
从根到叶子节点路径 1 ->2 代表数字 12 .
从根到叶子节点路径 1 ->3 代表数字 13 .
因此,数字总和 = 12 + 13 = 2 5
示例 2:
输入 : [ 4 , 9 , 0 , 5 , 1 ]
4
/ \
9 0
/ \
5 1
输出 : 1026
解释 :
从根到叶子节点路径 4 ->9 ->5 代表数字 495 .
从根到叶子节点路径 4 ->9 ->1 代表数字 491 .
从根到叶子节点路径 4 ->0 代表数字 40 .
因此,数字总和 = 495 + 491 + 40 = 1026 .

二、解题思路

DFS思路:

这道题目要求计算从根节点到每个叶子节点的路径所代表的数字之和。每条路径上的数字可以通过将路径上的节点值按顺序连接起来形成一个数字。遍历一棵树从根节点到叶子节点的所有路径,最容易想到的方法是使用深度优先搜索(DFS),因此这题使用DFS是最容易解决的。

解决方式是从根节点开始,沿着路径往下走时,当前节点的值可以通过父节点的值乘以10再加上当前节点的值来计算。默认根节点的父节点的值为0。当到达叶子节点时,将叶子节点的值加到一个全局变量中。这里以示例2为例,画个图来帮助理解。

BFS思路:
对于树的遍历,我们知道除了前序中序后续遍历以外,还有DFS和BFS,DFS上面已经讲过了,下面再来看一下BFS,他是一层一层的遍历的,就像下面这样

原理和上面DFS类似,每遍历一个结点,我们就要重新计算当前节点的值,那么当前节点的值就是父节点的值*10+当前节点的值。

三、代码实现

DFS代码:

以例二来测试,由于输入数组 [4, 9, 0, 5, 1] 没有明确表示空节点,假设它表示的是一棵完全二叉树的前序遍历结果。如果实际的二叉树结构与假设不符,可能会导致构建的二叉树不正确。在这种情况下,需要更详细的信息来正确构建二叉树。

cpp 复制代码
#include <iostream>
#include <vector>
#include <stack>

using namespace std;

// 定义二叉树节点结构
struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

// 辅助函数:根据前序遍历数组构建二叉树
TreeNode* buildTree(vector<int>& preorder, int& index, int n) {
    if (index >= n) {
        return nullptr;
    }
    TreeNode* root = new TreeNode(preorder[index++]);
    root->left = buildTree(preorder, index, n);
    root->right = buildTree(preorder, index, n);
    return root;
}

int sumNumbers(TreeNode* root) {
    // 如果根节点是空,直接返回0即可
    if (root == nullptr)
        return 0;

    // 两个栈,一个存储的是节点,一个存储的是节点对应的值
    stack<TreeNode*> nodeStack;
    stack<int> valueStack;

    // 全局的,统计所有路径的和
    int res = 0;

    nodeStack.push(root);
    valueStack.push(root->val);

    while (!nodeStack.empty()) {
        // 当前节点和当前节点的值同时出栈
        TreeNode* node = nodeStack.top();
        nodeStack.pop();
        int value = valueStack.top();
        valueStack.pop();

        if (node->left == nullptr && node->right == nullptr) {
            // 如果当前节点是叶子结点,说明找到了一条路径,把这条
            // 路径的值加入到全局变量res中
            res += value;
        } else {
            // 如果不是叶子节点就执行下面的操作
            if (node->right != nullptr) {
                // 把子节点和子节点的值分别加入到栈中,这里子节点的值
                // 就是父节点的值*10+当前节点的值
                nodeStack.push(node->right);
                valueStack.push(value * 10 + node->right->val);
            }
            if (node->left != nullptr) {
                nodeStack.push(node->left);
                valueStack.push(value * 10 + node->left->val);
            }
        }
    }

    return res;
}

int main() {
    // 输入数组
    vector<int> preorder = {4, 9, 0, 5, 1};
    int index = 0;

    // 构建二叉树
    TreeNode* root = buildTree(preorder, index, preorder.size());

    // 计算路径数字之和
    int result = sumNumbers(root);
    cout << "路径数字之和: " << result << endl;

    return 0;
}

DFS代码精简为递归:

cpp 复制代码
#include <iostream>
#include <vector>

using namespace std;

// 定义二叉树节点结构
struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

// 辅助函数:根据前序遍历数组构建二叉树
TreeNode* buildTree(vector<int>& preorder, int& index, int n) {
    if (index >= n) {
        return nullptr;
    }
    TreeNode* root = new TreeNode(preorder[index++]);
    root->left = buildTree(preorder, index, n);
    root->right = buildTree(preorder, index, n);
    return root;
}

// 辅助函数:计算从根到叶子节点的路径数字之和
void dfs(TreeNode* node, int currentSum, int& totalSum) {
    if (node == nullptr)
        return;

    // 计算当前路径的数字
    currentSum = currentSum * 10 + node->val;

    // 如果是叶子节点,将当前路径的数字加到总和中
    if (node->left == nullptr && node->right == nullptr) {
        totalSum += currentSum;
        return;
    }

    // 递归遍历左子树和右子树
    dfs(node->left, currentSum, totalSum);
    dfs(node->right, currentSum, totalSum);
}

int sumNumbers(TreeNode* root) {
    int totalSum = 0;
    dfs(root, 0, totalSum);
    return totalSum;
}

int main() {
    // 输入数组
    vector<int> preorder = {4, 9, 0, 5, 1};
    int index = 0;

    // 构建二叉树
    TreeNode* root = buildTree(preorder, index, preorder.size());

    // 计算路径数字之和
    int result = sumNumbers(root);
    cout << "路径数字之和: " << result << endl;

    return 0;
}

BFS代码:

cpp 复制代码
#include <iostream>
#include <vector>
#include <queue>

using namespace std;

// 定义二叉树节点结构
struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

// 辅助函数:根据前序遍历数组构建二叉树
TreeNode* buildTree(vector<int>& preorder, int& index, int n) {
    if (index >= n) {
        return nullptr;
    }
    TreeNode* root = new TreeNode(preorder[index++]);
    root->left = buildTree(preorder, index, n);
    root->right = buildTree(preorder, index, n);
    return root;
}

int sumNumbers(TreeNode* root) {
    // 边界条件的判断
    if (root == nullptr)
        return 0;

    queue<TreeNode*> nodeQueue;
    queue<int> valueQueue;
    int res = 0;

    nodeQueue.push(root);
    valueQueue.push(root->val);

    while (!nodeQueue.empty()) {
        // 节点和节点对应的值同时出队
        TreeNode* node = nodeQueue.front();
        nodeQueue.pop();
        int value = valueQueue.front();
        valueQueue.pop();

        if (node->left == nullptr && node->right == nullptr) {
            // 如果当前节点是叶子结点,说明找到了一条路径,把这条
            // 路径的值加入到全局变量res中
            res += value;
        } else {
            // 如果不是叶子节点就执行下面的操作
            if (node->left != nullptr) {
                // 把子节点和子节点的值分别加入到队列中,这里子节点的值
                // 就是父节点的值*10+当前节点的值
                nodeQueue.push(node->left);
                valueQueue.push(value * 10 + node->left->val);
            }
            if (node->right != nullptr) {
                nodeQueue.push(node->right);
                valueQueue.push(value * 10 + node->right->val);
            }
        }
    }

    return res;
}

int main() {
    // 输入数组
    vector<int> preorder = {4, 9, 0, 5, 1};
    int index = 0;

    // 构建二叉树
    TreeNode* root = buildTree(preorder, index, preorder.size());

    // 计算路径数字之和
    int result = sumNumbers(root);
    cout << "路径数字之和: " << result << endl;

    return 0;
}

这道题目要求计算从根节点到每个叶子节点的路径所代表的数字之和。每条路径上的数字可以通过将路径上的节点值按顺序连接起来形成一个数字。我们要做的就是把这每个数字加起来。使用深度优先搜索(DFS)应该是最容易理解的,因为每条路径也可以被想象成一个链表,每个链表代表一个数字,然后把所有链表所代表的数字加起来就是这题要求的结果。

相关推荐
Python机器学习AI4 分钟前
分类模型的预测概率解读:3D概率分布可视化的直观呈现
算法·机器学习·分类
吕小明么1 小时前
OpenAI o3 “震撼” 发布后回归技术本身的审视与进一步思考
人工智能·深度学习·算法·aigc·agi
大胆飞猪1 小时前
C++9--前置++和后置++重载,const,日期类的实现(对前几篇知识点的应用)
c++
1 9 J1 小时前
数据结构 C/C++(实验五:图)
c语言·数据结构·c++·学习·算法
程序员shen1616111 小时前
抖音短视频saas矩阵源码系统开发所需掌握的技术
java·前端·数据库·python·算法
夕泠爱吃糖1 小时前
C++中如何实现序列化和反序列化?
服务器·数据库·c++
长潇若雪1 小时前
《类和对象:基础原理全解析(上篇)》
开发语言·c++·经验分享·类和对象
汝即来归1 小时前
选择排序和冒泡排序;MySQL架构
数据结构·算法·排序算法
咒法师无翅鱼2 小时前
【定理证明工具调研】Coq, Isabelle and Lean.
算法
风清云淡_A2 小时前
【java基础系列】实现数字的首位交换算法
java·算法