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

news2024/11/17 21:17:21

一、题目

        给定一个二叉树,它的每个结点都存放一个 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] 没有明确表示空节点,假设它表示的是一棵完全二叉树的前序遍历结果。如果实际的二叉树结构与假设不符,可能会导致构建的二叉树不正确。在这种情况下,需要更详细的信息来正确构建二叉树。

#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代码精简为递归:

#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代码:

#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)应该是最容易理解的,因为每条路径也可以被想象成一个链表,每个链表代表一个数字,然后把所有链表所代表的数字加起来就是这题要求的结果。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2175010.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CF补题第二天

题1 先来一道最短路热身 题目描述&#xff1a; 思路&#xff1a;第一眼SPFA&#xff0c;结果直接超时&#xff0c;正解思路&#xff1a;每一条边只走一次&#xff0c;那么我们找出不同的连通块&#xff0c;然后拓扑排序求最短路&#xff08;因为无环&#xff09;&#xff0c;…

有问题未解决(9.28)

#include <stdio.h> int main() {int a 1;int b 2;int c 3;int arr[] { a,b,c };arr[0] 10;printf("%d\n", a);//打印结果为1&#xff1b;return 0; } 颠覆认知了&#xff0c;或许也没有颠覆 arr是一个int类型的数组&#xff0c;他存的就是一个数&…

Android——ContentObserver监听短信

概述 内容观察器ContentObserver给目标内容注册一个观察器&#xff0c;目标内容的数据一旦发生变化&#xff0c;观察器规定好的动作马上触发&#xff0c;从而执行开发者预先定义的代码。 思路 注册一个监听 getContentResolver().registerContentObserver(uri, true, mObser…

QT+ESP8266+STM32项目构建三部曲三--QT从环境配置到源程序的解析

一、阿里云环境配置 大家在编写QT连接阿里云的程序之前&#xff0c;先按照下面这篇文章让消息可以在阿里云上顺利流转 QTESP8266STM32项目构建三部曲二--阿里云云端处理之云产品流转-CSDN博客文章浏览阅读485次&#xff0c;点赞7次&#xff0c;收藏4次。创建两个设备&#xff…

找不到msvcp110.dll怎么办,总结6种解决msvcp110.dll的方法

在电脑使用过程中&#xff0c;我们可能会遇到各种各样的问题&#xff0c;其中之一就是系统提示某个文件丢失。msvcp110.dll丢失是一个比较常见的问题&#xff0c;它可能导致某些程序无法正常运行。那么&#xff0c;如何解决这个问题呢&#xff1f;本文将详细介绍6种修复msvcp11…

手把手教你用PyTorch从零训练自己的大模型(非常详细)零基础入门到精通,收藏这一篇就够了

长按关注《AI科技论谈》 LLM是如今大多数AI聊天机器人的核心基础&#xff0c;例如ChatGPT、Gemini、MetaAI、Mistral AI等。这些LLM背后的核心是Transformer架构。 本文介绍如何一步步使用PyTorch从零开始构建和训练一个大型语言模型&#xff08;LLM&#xff09;。该模型以Tra…

OpenHarmony标准系统上实现对rk系列芯片NPU的支持(npu使用)

在上篇文章中&#xff0c;我们学习了移植rk的npu驱动到OpenHarmony提供的内核。本文我们来学习如何在OpenHarmony标准系统rk系列芯片如何使用npu OpenHarmony RK系列芯片运行npu测试用例 在移植npu驱动到OpenHarmony之后&#xff0c;来运行npu样例进行简单测试 1.O 测试准备…

【球形空间产生器】

题目 代码 #pragma GCC optimize(3) #include <bits/stdc.h> using namespace std; const double eps 1e-6; const int N 12; double g[N][N]; double ss[N]; int n; void gauss() {int c, r, t;for(c 1, r 1; c < n; c){int t r;for(int i r1; i < n; i)i…

Wayfair封号的常见原因及解决方案解析

近期关于Wayfair账号封禁的问题引发了广泛讨论。许多用户报告称&#xff0c;他们的Wayfair账户被突然封禁&#xff0c;这一现象不仅影响了用户的购物体验&#xff0c;也对Wayfair的品牌形象造成了一定的冲击。本文将深入探讨Wayfair封号的原因&#xff0c;并提出相应的解决方案…

【SpringCloud】服务注册/服务发现-Eureka

服务注册/服务发现-Eureka 1. 背景1.1 问题描述1.2 解决思路1.3 什么是注册中⼼1.4 CAP理论1.5 常⻅的注册中⼼ 2. Eureka 介绍3. 搭建Eureka Server 1. 背景 1.1 问题描述 上个章节的例⼦中可以看到, 远程调⽤时, 我们的URL是写死的 String url "http://127.0.0.1:90…

Flink CDC实时同步MySQL到Doris

文章目录 1.开启Flink集群2.MySQL准备数据并开启Binlog3.FlinkCDC 提交任务到集群任务提交同步变更库表迁移 问题总结 Apache Flink CDC&#xff08;Change Data Capture&#xff09;是一个用于捕获和跟踪数据库更改的技术&#xff0c;它能够实时地从数据库中获取数据变更&…

★ C++进阶篇 ★ map和set

Ciallo&#xff5e;(∠・ω< )⌒☆ ~ 今天&#xff0c;我将继续和大家一起学习C进阶篇第四章----map和set ~ ❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️ 澄岚主页&#xff1a;椎名澄嵐-CSDN博客 C基础篇专栏&#xff1a;★ C基础篇 ★_椎名澄嵐的博客-CSDN博…

AVLTree【c++实现】

目录 AVL树1.AVL树的概念2.AVLTree节点的定义3.AVLTree的插入4.AVLTree的旋转4.1左单旋4.2右单旋4.3左右双旋4.4右左双旋 5.AVLTree的验证6.AVLTree的性能 AVL树 AVLTree的代码实现连接&#xff1a; AVLTree 代码链接 1.AVL树的概念 学习了二叉搜索树之后&#xff0c;我们知…

18年408数据结构

第一题&#xff1a; 解析&#xff1a;这道题很简单&#xff0c;按部就班的做就可以了。 画出S1&#xff0c;S2两个栈的情况&#xff1a; S1: S2: 2 3 - 8 * 5 从S1中依次弹出两个操作数2和3&a…

甄选范文“论企业应用系统的数据持久层架构设计”,软考高级论文,系统架构设计师论文

论文真题 数据持久层(Data Persistence Layer)通常位于企业应用系统的业务逻辑层和数据源层之间,为整个项目提供一个高层、统一、安全、并发的数据持久机制,完成对各种数据进行持久化的编程工作,并为系统业务逻辑层提供服务。它能够使程序员避免手工编写访问数据源的方法…

IDEA 高版本创建 Spring Boot 项目选不到 java 8

一、场景分析 现在高版本的 IDEA&#xff0c;创建 Spring Boot 项目时常常会选不到 Java 8&#xff1a; 直接使用 Java 17 新建项目&#xff0c;又会报错&#xff1a; Selected version of Java 17 is not supported by the project SDK 1.8. Either choose a lower version o…

Linux增加一个回收站功能(实用功能)

在linux中,默认是没有回收站的概念的,文件被删除之后,就没有了,很难进行恢复,本章教程,教你如何在linux中安装一个回收站功能,让你的文件即使删掉了,也有即使找回来。 一、安装插件 需要注意的是, python版本需要大于3.8,否则安装之后可能无法使用。 1、下载插件 ht…

基于Qt的多功能串口通信工具分享:实时数据收发与波形绘制

需要工程源码请私信 基于 Qt 框架开发的多功能串口通信工具&#xff0c;旨在为用户提供稳定、流畅的串口数据收发体验。该工具不仅支持基本的串口通信功能&#xff0c;还集成了定时发送、多线程数据处理、粘包问题解决、实时波形绘制等多种高级功能。通过使用 QSerialPort 进行…

录屏小白福音!三款神器助你轻松上手

生活工作中&#xff0c;需要借助录屏功能越来越家常便饭了&#xff0c;选择录屏软件时&#xff0c;主要考虑的是软件的易用性、功能以及用户评价等因素。以下是如何进行录屏的步骤&#xff0c;以及推荐的四个录屏软件的使用说明&#xff1a;关于如何录屏的步骤操作&#xff0c;…

使用 PowerShell 命令更改 RDP 远程桌面端口(无需修改防火墙设置)

节选自原文&#xff1a;Windows远程桌面一站式指南 | BOBO Blog 原文目录 什么是RDP&#xfffc;开启远程桌面 检查系统版本启用远程桌面连接Windows 在Windows电脑上在MAC电脑上在Android或iOS移动设备上主机名连接 自定义电脑名通过主机名远程桌面使用Hosts文件自定义远程主…