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,一经查实,立即删除!

相关文章

Golang之路---04 项目管理——编码规范

本文根据个人编码习惯以及网络上的一些文章&#xff0c;整理了一些大家能用上的编码规范&#xff0c;可能是一些主流方案&#xff0c;但不代表官方。 1. 文件命名 由于 Windows平台文件名不区分大小写&#xff0c;所以文件名应一律使用小写 不同单词之间用下划线分词&#xf…

第20周 服务容错-Hystrix

RabbitMQ 安装 1. 首先在Linux上进行一些软件的准备工作&#xff0c;yum下来一些基础的软件包 yum install build-essential openssl openssl-devel unixODBC unixODBC-devel make gcc gcc-c kernel-devel 2. 下载RabbitMQ所需软件包&#xff08;本神在这里使用的是 RabbitM…

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

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

二叉树的直径 LeetCode热题100

题目 给你一棵二叉树的根节点&#xff0c;返回该树的 直径 。 二叉树的 直径 是指树中任意两个节点之间最长路径的 长度 。这条路径可能经过也可能不经过根节点 root 。 两节点之间路径的 长度 由它们之间边数表示。 思路 分析二叉树的直径&#xff0c;无非是一个节点加上…

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_…

C#仿热血江湖GClass

目录 1 GClass2 1.1 method 2 GClass35 2.1.1 保存人物的数据 2.1.2 method_0 GClass2 using System; public class GClass2 : IDisposable {

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是代价…

C语言编程工具软件推荐!

1、VS(Visual Studio) [VS是目前最受欢迎的适用于Windows平台应用程序的综合开发环境&#xff0c;由于大多数同学使用的都是Windows操作系统&#xff0c;因此VS非常适合大家。在日常课堂和考试中&#xff0c;我们使用的VS2010支持多种不同的编程语言&#xff0c;VS2010最初支持…

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…