LeetCode113. 路径总和 II

113. 路径总和 II

文章目录

      • [113. 路径总和 II](https://leetcode.cn/problems/path-sum-ii/)
        • 一、题目
        • 二、题解
          • 方法一:递归
          • 另一种递归版本
          • 方法二:迭代


一、题目

给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。

叶子节点 是指没有子节点的节点。

示例 1:

img

输入:root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
输出:[[5,4,11,2],[5,8,4,5]]

示例 2:

img

输入:root = [1,2,3], targetSum = 5
输出:[]

示例 3:

输入:root = [1,2], targetSum = 0
输出:[]

提示:

  • 树中节点总数在范围 [0, 5000]
  • -1000 <= Node.val <= 1000
  • -1000 <= targetSum <= 1000

二、题解

方法一:递归

算法思路

  1. 我们需要遍历二叉树中所有从根节点到叶子节点的路径,以找出满足路径和等于目标和的路径。这提示我们可以使用深度优先搜索(DFS)来遍历树的所有可能路径。

  2. 我们可以在递归过程中维护一个当前路径的和 count,从根节点开始,每到一个节点,我们将该节点的值在count 上进行减法处理。

  3. 如果当前节点是叶子节点(即没有左右子节点),我们检查 count 是否等于0。如果是,我们将当前路径添加到结果中。

  4. 在递归过程中,我们需要传递当前路径 path,结果数组 result,当前路径的和 count,以及当前节点 root

具体实现

class Solution {
public:void findPath(TreeNode *root, vector<vector<int>>&result, vector<int>& path, int count){if(root == nullptr) return;path.push_back(root->val);count -= root->val;if(count == 0 && !root->left && !root->right){result.push_back(path);}if(root->left){findPath(root->left, result, path, count);}if(root->right){findPath(root->right, result, path, count);}path.pop_back(); // 回溯,移除当前节点,尝试其他路径}vector<vector<int>> pathSum(TreeNode* root, int targetSum) {vector<vector<int>> result;vector<int> path;if(root == nullptr) return result;findPath(root, result, path, targetSum);return result;}
};

算法分析

  • 时间复杂度:遍历整个二叉树,每个节点只访问一次,所以时间复杂度为 O(N),其中 N 是树中的节点数。

  • 空间复杂度:在递归过程中,我们使用了 path 数组来存储当前路径,最坏情况下,路径长度达到树的深度,所以空间复杂度为 O(H),其中 H 是树的高度。在结果数组中,我们存储了满足条件的路径,最坏情况下可能会有 O(N) 个路径,所以结果数组的空间复杂度也是 O(N)。

另一种递归版本

因为cpp的特性,通过去掉 vector<int>& 中的引用符号,我可以在每个递归层次中都创建了一个新的 path 向量,这样可以确保在不同的递归路径之间不会共享相同的 path 对象,相当于进行了回溯。

/*** 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 findPath(TreeNode *root, vector<vector<int>>&result, vector<int> path, int count){if(root == nullptr) return;path.push_back(root->val);count -= root->val;if(count == 0 && !root->left && !root->right){result.push_back(path);}if(root->left){findPath(root->left, result, path, count);}if(root->right){findPath(root->right, result, path, count);}}vector<vector<int>> pathSum(TreeNode* root, int targetSum) {vector<vector<int>> result;vector<int> path;if(root == nullptr) return result;int count = targetSum;findPath(root, result, path, count);return result;}
};
方法二:迭代

算法思路

  1. 我们使用中序遍历来遍历树的节点,同时维护两个栈:St 用于保存遍历节点的信息,pathSt 用于保存当前路径的节点值。
  2. 初始时,我们将根节点 root 和对应的路径值 root->val 入栈,表示从根节点开始的路径。
  3. 在每一次循环中,我们从 St 栈中取出一个节点,同时从 pathSt 中取出与该节点对应的路径。
  4. 我们检查该节点是否为叶子节点,如果是叶子节点并且路径值等于 targetSum,则将该路径保存到 result 中。
  5. 如果不是叶子节点,我们将其左子节点和右子节点(如果存在的话)入栈,并更新路径值。
  6. 重复以上步骤直至 St 栈为空。

具体实现

class Solution {
public:vector<vector<int>> pathSum(TreeNode* root, int targetSum) {vector<vector<int>> result; // 用于存储符合条件的路径stack<pair<TreeNode*, int>> St; // 用于深度优先搜索的栈,同时保存节点和路径和stack<vector<int>> pathSt; // 用于保存路径的栈if (root == nullptr) return result; // 处理根节点为空的情况// 初始化,将根节点和路径和入栈St.push(pair<TreeNode*, int>(root, root->val));vector<int> temp;temp.push_back(root->val);pathSt.push(temp);while (!St.empty()) {pair<TreeNode*, int> node = St.top(); St.pop(); // 弹出栈顶节点vector<int> pathT = pathSt.top(); pathSt.pop(); // 弹出栈顶路径// 如果是叶子节点且路径和等于targetSum,将路径保存到result中if (!node.first->left && !node.first->right && node.second == targetSum) {result.push_back(pathT);}// 将右子节点入栈,更新路径和,并将路径入栈if (node.first->right) {St.push(pair<TreeNode*, int>(node.first->right, node.second + node.first->right->val));vector<int> newPathT = pathT;newPathT.push_back(node.first->right->val);pathSt.push(newPathT);}// 将左子节点入栈,更新路径和,并将路径入栈if (node.first->left) {St.push(pair<TreeNode*, int>(node.first->left, node.second + node.first->left->val));vector<int> newPathT = pathT;newPathT.push_back(node.first->left->val);pathSt.push(newPathT);}}return result; // 返回所有满足条件的路径}
};

算法分析

  • 时间复杂度:每个节点最多访问一次,所以时间复杂度为 O(N),其中 N 是树的节点数。
  • 空间复杂度:栈的最大空间取决于树的高度,所以空间复杂度为 O(H),其中 H 是树的高度。

简化版本

class Solution {
public:vector<vector<int>> pathSum(TreeNode* root, int targetSum) {vector<vector<int>> result;vector<int> path;stack<TreeNode*> TreeSt;stack<vector<int>> pathSt;if(root == nullptr) return result;// 初始化TreeSt.push(root);vector<int> temp;temp.push_back(root->val);pathSt.push(temp);while(!TreeSt.empty()){TreeNode *node = TreeSt.top();TreeSt.pop();vector<int> pathT = pathSt.top();pathSt.pop();if(!node->left && !node->right && accumulate(pathT.begin(), pathT.end(), 0) == targetSum) {	//这里直接计算路径上的总和result.push_back(pathT);}if(node->right){TreeSt.push(node->right);vector<int> newPathT = pathT; newPathT.push_back(node->right->val);pathSt.push(newPathT);}if(node->left){TreeSt.push(node->left);vector<int> newPathT = pathT; newPathT.push_back(node->left->val);pathSt.push(newPathT);}}return result;}
};

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

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

相关文章

java+python企业会议在线办公微信小程序 ia505

一、小程序端功能 该部分内容提供员工注册、员工资料修改、通知公告、部门信息、会议记录等等功能。 二、管理员管理功能 该部分内容包含了首页、个人中心、通知公告管理、员工管理、部门信息管理、职位信息管理、会议记录管理、待办事项管理、工资信息管理、留言板管理、系统管…

C++ 类型兼容规则

类型兼容规则是指在需要基类对象的任何地方&#xff0c;都可以使用公有派生类的对象来替代。 通过公有继承&#xff0c;派生类得到了基类中除构造函数和析构函数之外的所有成员。这样&#xff0c;公有派生类实际就具备了基类的所有功能&#xff0c;凡是基类能解决的问题&#x…

微信支付官方文档怎么看

博主介绍&#xff1a;✌全网粉丝3W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战&#xff0c;博主也曾写过优秀论文&#xff0c;查重率极低&#xff0c;在这方面有丰富的经验…

Cilium系列-14-Cilium NetworkPolicy 简介

系列文章 Cilium 系列文章 前言 今天我们进入 Cilium 安全相关主题, 介绍 Kubernetes 网络策略以及 CiliumNetworkPolicies 额外支持的内容。 网络策略(NetworkPolicy)的类型 默认情况下&#xff0c;Kubernetes 集群中的所有 pod 都可被其他 pod 和网络端点访问。 网络策…

Kafka3.0.0版本——Broker(Zookeeper服务端存储的Kafka相关信息)

目录 一、启动zookeeper集群及kafka集群服务启动1.1、先启动三台zookeeper集群服务&#xff0c;再启动三台kafka集群服务1.2、使用PrettyZoo连接zookeeper客户端工具 二、在zookeeper服务端存储的Kafka相关信息 一、启动zookeeper集群及kafka集群服务启动 1.1、先启动三台zook…

计算机成下一个土木了吗?

前些年抓住了互联网行业的红利期&#xff0c;进入大厂的员工&#xff0c;基本可以实现在一线城市买房扎根。 但反观现在&#xff0c;“被毕业、逃离互联网、躺平算了...”却成了这个行业的主旋律&#xff0c;不少人在谈论润到国企和外企去了&#xff0c;也放低了对工资的预期&…

LIME(可解释性分析方法)

目录 1.什么是LIME 2.思路 3.LIME在不同任务中的范式&#xff08;待补充&#xff09; 1.什么是LIME 简单理解&#xff1a; 对于分类任务&#xff1a;如下图所示&#xff0c;LIME可以列出分类结果&#xff0c;所依据特征对应给比重。 对于图像分类任务&#xff1a;如下图所示&a…

docker 配置 Mysql主从集群

Docker version 20.10.17, build 100c701 MySQL Image version: 8.0.32 Docker container mysql-master is source. mys ql-replica is replication. master source. replica slave.名称叫法不一样而已。 Choose one of the way&#xff0c;与replica同步数据两种情况&…

【Shell】基础语法(一)

文章目录 一、shell的介绍二、执行脚本三、shell的基本语法1. 变量的使用2. 变量的分类 一、shell的介绍 Shell的作用是解释执行用户的命令&#xff0c;用户输入一条命令&#xff0c;Shell就解释执行一条&#xff0c;这种方式称为交互式&#xff08;Interactive&#xff09;&a…

不规则文件转JSON

需求分析&#xff1a; 有时候&#xff0c;我们取出来的数据并不是一个规则的JSON文件&#xff0c;这个时候面对存库还是ES检索都是一个问题&#xff0c;所以我们就需要进行解析&#xff0c;然而用字符串分割是不现实的&#xff0c;我们需要一种快速的方法。 问题解决&#x…

Linux-centos花生壳实现内网穿透

Linux-centos花生壳实现内网穿透 官网教程 1.安装花生壳 下载网址 点击复制就可以复制下载命令了 wget "https://dl.oray.com/hsk/linux/phddns_5.2.0_amd64.rpm" -O phddns_5.2.0_amd64.rpm# 下载完成之后会多一个rpm文件 [rootlocalhost HuaSheng]# ls phddns_…

flask中的应用上下文

flask中的应用上下文 Flask应用上下文主要包含两个对象&#xff1a;current_app和g。这两个对象在处理请求期间都是全局可访问的&#xff0c;但在每个请求结束时都会被重置。 current_app&#xff1a;这是当前激活的Flask应用的实例。在大多数情况下&#xff0c;你可以将其视为…

刷题DAY16

题目一 给定两个字符串str1和str2&#xff0c;再给定三个整数ic、dc和rc&#xff0c;分别代表插入、删除和替换一个字符的代价&#xff0c;返回将str1编辑成str2的最小代价。【举例]str1"abc",str2“adc",ic5,dc3,rc2从“abc“编辑成adc",把b替换成d是代价…

zookeeper --- 高级篇

一、zookeeper 事件监听机制 1.1、watcher概念 zookeeper提供了数据的发布/订阅功能&#xff0c;多个订阅者可同时监听某一特定主题对象&#xff0c;当该主题对象的自身状态发生变化时(例如节点内容改变、节点下的子节点列表改变等)&#xff0c;会实时、主动通知所有订阅者 …

epoll、poll、select的原理和区别

select&#xff0c;poll&#xff0c;epoll都是IO多路复用的机制。I/O多路复用就是通过一种机制&#xff0c;一个进程可以监视多个描述符&#xff0c;一旦某个描述符就绪&#xff08;一般是读就绪或者写就绪&#xff09;&#xff0c;能够通知程序进行相应的读写操作。但select&a…

Markdown学习简记

目录 一、写Markdown的第0步 二、语法须知 标题 粗体强调 斜体 斜体同时粗体 删除线 高亮 代码 代码块 引用块 无序列表 有序列表 链接 表格 图片 分割线 目录生成 内联HTML代码 Typora常用快捷键 Typora的主题样式与检查元素 一、写Markdown的第…

Django Rest_Framework(三)

文章目录 1. 认证Authentication2. 权限Permissions使用提供的权限举例自定义权限 3. 限流Throttling基本使用可选限流类 4. 过滤Filtering5. 排序Ordering6. 分页Pagination可选分页器 7. 异常处理 ExceptionsREST framework定义的异常 8. 自动生成接口文档coreapi安装依赖设置…

Javaweb学习(2)

Javaweb学习 一、Maven1.1 Maven概述1.2 Maven简介1.3、Maven基本使用1.4、IDEA配置Maven1.6、依赖管理&依赖范围 二、MyBatis2.1 MyBatis简介2.2 Mybatis快速入门2.3、解决SQL映射文件的警告提示2.4、Mapper代理开发 三、MyBaits核心配置文件四、 配置文件的增删改查4.1 M…

Flink之RedisSink

在Flink开发中经常会有将数据写入到redis的需求,但是Flink官方并没有对应的扩展包,这个时候需要我们自己编译对应的jar资源,这个时候就用到了bahir,barhir是apahce的开源项目,是专门给spark和flink提供扩展包使用的,bahir官网,这篇文章就介绍下如何自己编译RedisSink扩展包. 下…

在tensorflow分布式训练过程中突然终止(终止)

问题 这是为那些将从服务器接收渐变的员工提供的培训功能&#xff0c;在计算权重和偏差后&#xff0c;将更新的渐变发送到服务器。代码如下&#xff1a; def train():"""Train CIFAR-10 for a number of steps."""g1 tf.Graph()with g1.as_de…