LeetCode 257. 二叉树的所有路径

LeetCode 257. 二叉树的所有路径

1、题目

题目链接:257. 二叉树的所有路径
给你一个二叉树的根节点 root ,按 任意顺序 ,返回所有从根节点到叶子节点的路径。
叶子节点 是指没有子节点的节点。

示例 1:
image.png

输入:root = [1,2,3,null,5]
输出:["1->2->5","1->3"]

示例 2:

输入:root = [1]
输出:["1"]

提示:

  • 树中节点的数目在范围 [1, 100] 内
  • -100 <= Node.val <= 100

2、深度优先搜索(递归实现)

思路

这道题目要求返回从二叉树的根节点到所有叶子节点的路径。一种直观的解法是使用深度优先搜索(DFS)。
在深度优先搜索遍历二叉树时,我们需要考虑当前的节点以及它的孩子节点。

  • 如果当前节点不是叶子节点,则在当前的路径末尾添加该节点,并继续递归遍历该节点的每一个孩子节点。
  • 如果当前节点是叶子节点,则在当前路径末尾添加该节点后我们就得到了一条从根节点到叶子节点的路径,将该路径加入到答案即可。

如此,当遍历完整棵二叉树以后我们就得到了所有从根节点到叶子节点的路径。

代码

#include <iostream>
#include <vector>
#include <string>

using namespace std;

//Definition for a binary tree node.
struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode() : val(0), left(nullptr), right(nullptr) {}
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
    TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
};

// 递归解法
class Solution {
public:
    void traversal(TreeNode* cur, vector<int>& path, vector<string>& result) {
        // 将当前节点的值添加到path中
        path.push_back(cur->val);

        // 判断当前节点是否是叶子节点(即没有左右子节点)
        if (cur->left == nullptr && cur->right == nullptr) {
            // 用于存储从根节点到当前叶子节点的路径。
            string sPath;
            // 将path里记录的路径转为string格式
            for (int i = 0; i < path.size() - 1; i++) {
                // 将path中的元素转换为字符串并添加到sPath中
                sPath += to_string(path[i]);
                // 添加箭头符号表示路径关系
                sPath += "->";
            }
            // 将path中的最后一个元素(即当前叶子节点的值)转换为字符串,并添加到sPath中
            sPath += to_string(path[path.size() - 1]);
            // 将sPath添加到result中
            result.push_back(sPath);
            return;
        }

        // 如果当前节点有左子节点
        if (cur->left) {
            // 递归遍历左子树
            traversal(cur->left, path, result);
            // 回溯,将左子节点从path中移除
            path.pop_back();
        }

        // 如果当前节点有右子节点
        if (cur->right) {
            // 递归遍历右子树
            traversal(cur->right, path, result);
            // 回溯,将右子节点从path中移除
            path.pop_back();
        }
    }

    vector<string> binaryTreePaths(TreeNode* root) {
        // 用于存储所有从根节点到叶子节点的路径
        vector<string> result;
        // 用于存储从根节点到当前节点的路径
        vector<int> path;
        
        if (root == nullptr) {
            return result;
        }
        traversal(root, path, result);
        return result;
    }
};

int main() {
    Solution s;
    TreeNode* root = new TreeNode(1);
    root->left = new TreeNode(2);
    root->right = new TreeNode(3);
    root->left->left = new TreeNode(4);
    root->left->right = new TreeNode(5);
    root->right->left = new TreeNode(6);
    root->right->right = new TreeNode(7);
    vector<string> result = s.binaryTreePaths(root);
    for (string path : result) {
        cout << path << endl;
    }
    return 0;
}

复杂度分析

  • 时间复杂度: O(n^2)
  • 空间复杂度: O(n^2)

3、深度优先搜索(递归实现精简版)

思路

这里需要注意在函数定义的时候 void traversal(TreeNode* cur, string path, vector<string>& result) ,定义的是string path,每次都是复制赋值,不用使用引用,否则就无法做到回溯的效果。
在** **traversal(cur->left, path + "->", result); 中的 path + "->"隐藏了回溯操作。 每次函数调用完,path 依然是没有加上 "->" 的,这就是回溯了。

代码

class Solution {
private:
    void traversal(TreeNode* cur, string path, vector<string>& result) {
        // 将当前节点的值添加到path中
        path += to_string(cur->val);

        // 判断当前节点是否是叶子节点(即没有左右子节点)
        if (cur->left == nullptr && cur->right == nullptr) {
            // 将path添加到result中
            result.push_back(path);
            return;
        }

        // 如果当前节点有左子节点
        if (cur->left) {
            // 递归遍历左子树,路径加上 "->"
            // 注意:这里的path加上 "->" 并不是在原path的基础上添加,而是直接在path末尾添加 "->"
            // 这样每次函数调用完,path依然是没有加上"->" 的,这里隐藏的是回溯的操作

            traversal(cur->left, path + "->", result);
        }

        // 如果当前节点有右子节点
        if (cur->right) {
            // 递归遍历右子树,路径加上 "->"
            traversal(cur->right, path + "->", result);
        }
    }

public:
    vector<string> binaryTreePaths(TreeNode* root) {
        // 用于存储所有从根节点到叶子节点的路径
        vector<string> result;
        if (root == nullptr) {
            return result;
        }
        // 用于存储从根节点到当前节点的路径
        string path;
        traversal(root, path, result);
        return result;
    }
};

复杂度分析

  • 时间复杂度: O(n^2)
  • 空间复杂度: O(n^2)

4、广度优先搜索(迭代法)

思路

我们也可以用广度优先搜索来实现。我们维护一个队列,存储节点以及根到该节点的路径。一开始这个队列里只有根节点。在每一步迭代中,我们取出队列中的首节点,如果它是叶子节点,则将它对应的路径加入到答案中。如果它不是叶子节点,则将它的所有孩子节点加入到队列的末尾。当队列为空时,广度优先搜索结束,我们即能得到答案。

代码

class Solution {
public:
    vector<string> binaryTreePaths(TreeNode* root) {
        // 用于存储所有从根节点到叶子节点的路径
        vector<string> paths;
        if (root == nullptr) {
            return paths;
        }

        // 使用队列存储树的遍历节点和对应的路径
        queue<TreeNode*> queTree;
        queue<string> quePath;

        // 初始时将根节点和根节点的值加入队列
        queTree.push(root);
        quePath.push(to_string(root->val));

        while (!queTree.empty()) {
            // 取出队首节点和对应的路径
            TreeNode* node = queTree.front();
            queTree.pop();
            string path = quePath.front();
            quePath.pop();

            // 如果当前节点是叶子节点,则将当前路径添加到paths中
            if (node->left == nullptr && node->right == nullptr) {
                paths.push_back(path);
            }

            // 如果当前节点有左子节点,则将左子节点和更新后的路径加入队列
            if (node->left) {
                queTree.push(node->left);
                quePath.push(path + "->" + to_string(node->left->val));
            }

            // 如果当前节点有右子节点,则将右子节点和更新后的路径加入队列
            if (node->right) {
                queTree.push(node->right);
                quePath.push(path + "->" + to_string(node->right->val));
            }
        }
        return paths;
    }
};

复杂度分析

  • 时间复杂度: O(n^2)
  • 空间复杂度: O(n^2)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++:内存管理

C:内存管理 一、C/C内存分布二、C语言中动态内存管理方式&#xff1a;malloc/calloc/realloc/free三、C内存管理方式1.new/delete操作内置类型2.new和delete操作自定义类型 四、operator new与operator delete函数&#xff08;重点&#xff09;五、new和delete的实现原理1.内置…

Unity曲线插件Dreamteck Splines生成曲线Mesh

一、需求 脱离编辑器&#xff0c;运行时添加点&#xff0c;动态生成管道、线缆等曲线Mesh。 二、Dreamteck Splines简单运用 这方面资料不多&#xff0c;只有官方文档全英参考&#xff0c;而且又介绍得不详细。 2个重要组件介绍&#xff1a; SplineComputer&#xff1a; 最…

系统运维(虚拟化)

1.VLAN VLAN&#xff08;Virtual Local Area Network&#xff09;即虚拟局域网&#xff0c;是将一个物理的LAN在逻辑上划分成多个广播域的通信技术。 每个VLAN是一个广播域&#xff0c;VLAN内的主机间可以直接通信&#xff0c;而VLAN间则不能直接互通。这样&#xff0c;广播报…

987: 输出用先序遍历创建的二叉树是否为完全二叉树的判定结果

解法&#xff1a; 一棵二叉树是完全二叉树的条件是&#xff1a; 对于任意一个结点&#xff0c;如果它有右子树而没有左子树&#xff0c;则这棵树不是完全二叉树。 如果一个结点有左子树但是没有右子树&#xff0c;则这个结点之后的所有结点都必须是叶子结点。 如果满足以上条…

1010: 折半查找的实现

解法&#xff1a; #include<iostream> #include<vector> using namespace std; void solve() {int n;cin >> n;vector<int> vec(n);for (int& x : vec) cin >> x;int x;cin >> x;int l 0, r n-1, cnt 0;while (l < r) {cnt;int…

Ubuntu22.04下安装kafka_2.12-2.6.0并运行简单实例

目录 一、版本信息 二、安装Kafka 1. 将Kafka安装包移到下载目录中 2. 安装Kafka并确保hadoop用户对Kafka目录有操作权限 三、启动Kafka并测试Kafka是否正常工作 1. 启动Kafka 2. 测试Kafka是否正常工作 一、版本信息 虚拟机产品&#xff1a;VMware Workstation 17 Pro…

一套C语言开发的 PACS影像系统源码 PACS系统的基本概念、系统业务流程

PACS系统基本概念 PACS&#xff0c;全称 Picture Archiving and Communication Systems&#xff0c;中文意为影像归档和通信系统。它是应用于医院影像科室的一种系统&#xff0c;主要任务是把日常产生的各种医学影像&#xff08;包括核磁&#xff0c;CT&#xff0c;超声&#…

Faststone Capture:高效屏幕捕获神器评测【AI写作】

首先&#xff0c;这篇文章是基于笔尖AI写作进行文章创作的&#xff0c;喜欢的宝子&#xff0c;也可以去体验下&#xff0c;解放双手&#xff0c;上班直接摸鱼~ 按照惯例&#xff0c;先介绍下这款笔尖AI写作&#xff0c;宝子也可以直接下滑跳过看正文~ 笔尖Ai写作&#xff1a;…

Java毕设之基于SpringBoot的在线拍卖系统

运行环境 开发语言:java 框架:springboot&#xff0c;vue JDK版本:JDK1.8 数据库:mysql5.7(推荐5.7&#xff0c;8.0也可以) 数据库工具:Navicat11 开发软件:idea/eclipse(推荐idea) 系统详细设计 管理员功能模块 管理员登录&#xff0c;管理员通过输入用户名、密码、角色等信…

AI日报:干翻AI PC!苹果M4芯片首发;GoEnhance可生成粘土风格视频;DeepSeek-V2模型已在魔搭社区开源

欢迎来到【AI日报】栏目!这里是你每天探索人工智能世界的指南&#xff0c;每天我们为你呈现AI领域的热点内容&#xff0c;聚焦开发者&#xff0c;助你洞悉技术趋势、了解创新AI产品应用。 新鲜AI产品点击了解&#xff1a;AIbase - 智能匹配最适合您的AI产品和网站 1、干翻AI …

Zip压缩归档库-libzip介绍

1.简介 libzip是一个C库&#xff0c;用于读取、创建和修改zip格式的压缩文件。它支持从zip文件中读取、写入、添加和删除文件&#xff0c;还支持密码保护的zip文件。libzip是跨平台的&#xff0c;可以在多种操作系统上使用&#xff0c;包括Linux、Windows和macOS。 常用接口介…

【Ping】Windows 网络延迟测试 ping 、telnet、tcping 工具

ping 命令 属于网络层的ICMP协议&#xff0c;只能检查 IP 的连通性或网络连接速度&#xff0c; 无法检测IP的端口状态。 telnet telnet命令&#xff0c;属于应用层的协议&#xff0c;用于远程登录&#xff0c;也可用于检测IP的端口状态。但是功能有限&#xff0c;只能检测一时…

【OpenHarmony 实战开发】 做一个 loading加载动画

本篇文章介绍了如何实现一个简单的 loading 加载动画&#xff0c;并且在文末提供了一个 demo 工程供读者下载学习。作为一个 OpenHarmony 南向开发者&#xff0c;接触北向应用开发并不多。北向开发 ArkUI 老是改来改去&#xff0c;对笔者这样的入门选手来说学习成本其实非常大&…

网页主题自动适配:网页跟随系统自动切换主题

主题切换是网站设计中一个非常有趣的功能&#xff0c;它允许用户在多种预先设计的样式之间轻松切换&#xff0c;以改变网站的视觉表现。最常见的就是白天和黑夜主题的切换&#xff0c;用户可以根据自己的喜好进行设置。 除了让用户手动去切换主题外&#xff0c;如果能够让用户第…

Vue从入门到实战Day03

一、生命周期 1. 生命周期四个阶段 思考&#xff1a; ①什么时候可以发送初始化渲染请求&#xff1f; 答&#xff1a;越早越好&#xff0c;在创建阶段后 ②什么时候可以开始操作DOM&#xff1f; 答&#xff1a;至少DOM得渲染出来&#xff0c;在挂载阶段结束后。 Vue生命周…

Python从0到POC编写--实用小脚本02

爆破脚本&#xff1a; 爆破脚本也是我们经常使用的东西 这里就简单讲讲后台爆破脚本的编写吧 在编写之前&#xff0c;我们先通过访问网站去看看情况 首先我们可以先登录看看 输入账号 admin &#xff0c;密码 12345 后 登录失败&#xff0c;提示 用户名或密码错误 在输入…

MultiBooth:文本驱动的多概念图像生成技术

在人工智能的领域&#xff0c;将文本描述转换为图像的技术正变得越来越先进。最近&#xff0c;一个由清华大学和Meta Reality Labs的研究人员组成的团队&#xff0c;提出了一种名为MultiBooth的新方法&#xff0c;它能够根据用户的文本提示&#xff0c;生成包含多个定制概念的图…

去除视频背景音乐或人物声音的4种方法,建议收藏

你是否曾想移除视频中令人分心的声音呢&#xff1f;对于需要裁剪声音或去除背景噪音的视频来说&#xff0c;消音是一种非常有用的技能。那么&#xff0c;视频怎么消除声音&#xff1f;看看下文就知道了。 方法一&#xff1a;使用 智优影 去除视频中的音频 在线转换工具不仅支持…

怎样选择IT外包公司?需要注意什么?

随着网络化、数字化、智能化快速发展&#xff0c;一部分企业成立自己的IT部门&#xff0c;负责各个科室的网络安全&#xff0c;大部分企业把网络安全、数据安全&#xff0c;外包给专业的IT外包公司&#xff0c;既提升了办公效率&#xff0c;企业又能把主要精力放在发展核心业务…

【C】语⾔内存函数--超详解

1. memcpy 使⽤和模拟实现 void * memcpy ( void * destination, const void * source, size_t num ); 函数memcpy从source的位置开始向后复制num个字节的数据到destination指向的内存位置。 这个函数在遇到 \0 的时候并不会停下来。 如果source和destination有任何的重叠&am…
最新文章