二叉树路径查找

news2025/1/17 4:43:15

题目描述:给定一棵二叉树(结构如下),其中每个节点值为整数。给定一个值 K,求所有满足如下条件的路径并将路径上节点的值打印出来:

        1、路径方向必须向下,即只能从父节点指向子节点

        2、路径并不是必须从根节点开始或在叶节点结束。即树上任意节点开始向下走到任意节点的路径都 允许。

        3、路径上的节点得分之和等于给定值 K。节点得分=节点值+节点所在层(根节点为 0,之后每层+1)。

示例:给定二叉树[5,3,7,9,null,11,2,4,-1, null,null,2,-2],K=16

输出

5 3 9 -1

5 7 2 2

3 9 4

解释:如第一个路径 5 3 9 -1,路径上节点得分分别为 5+0,3+1,9+2,-1+3,和为 22

输入格式:第一行为一个整数 K,第二行为一个二叉树的层次遍历序列,其中空子树用 null 表示,每两个数字或者 null 之间用空格分隔,例如:

22

5 3 7 9 null 11 2 4 -1 null null 2 -2

需要注意的是,null 节点的子节点不会显式的写出来,如上例中第二行值为 3 的节点的右子树为空, 则该右空子树的左右子树不会再以 null 表示。

输出格式:分为多行,每行为一个满足条件的路径上节点的值的序列,例如:

5 3 9 -1

5 7 2 2

3 9 4

现有如下输入

35

5 4 8 11 null 13 4 7 2 null null 5 1 8 null 7 10 6 null null null 

请用程序将正确结果输出

思路:我们先弱化问题,如果我们现在已经有一棵建好的树,此时要我们输出树上所有向下路径和为K的路径;为了解决这个问题,我们再弱化问题,假设只要求从根节点出发的路径,那么从根节点开始,我们当前的路径和为根节点的val值,已经经过的节点为根节点,下一步我们可以选择的是向左或者向右,那么对于后续的节点,也是一样的,这样其实就是一个DFS问题。为了能够输出和为K的路径,我们需要sum存储当前和路径和以及一个容器vector存储当前经历过的节点。我们的DFS雏形就有了 DFS(TreeNode* root, int sum, vector<int> nums)。 

现在我们强化条件,回到不要求从根节点出发,我们增加一个mark位,用于指示现在是否是在路径内,如果在路径内,那么当前遍历到的节点值必须累加,并加其加入路径节点的容器,否则的话,可以选择不加,也可以选择加,DFS变为 DFS(TreeNode* root, int sum, vector<int> nums. bool in_path)

现在还剩下最后一个建树的问题了,既然是BFS序那么直接按照BFS的方式建树就好啦。

#include<bits/stdc++.h>
using namespace std; 

struct Node{
	int num;
	Node *lchild, *rchild;
	bool have_l = false, have_r = false; //由于我们没有办法通过lchild、rchild是否为null判断是否有孩子,所以需要手动设置标记位
	Node(int num, Node *lchild, Node *rchild){
		this -> num = num;
		this -> lchild = lchild;
		this -> rchild = rchild;
	}
};

void DFS(Node* root, bool start, int sum, vector<int>& choices, int k){
	if(!root){
		return;
	}
	if(!start){//如果路径还没开始,则当前节点可以选择不加入
		DFS(root -> lchild, false, 0, choices, k);
		DFS(root -> rchild, false, 0, choices, k);
	}
	sum = sum + root ->num;//累计上当前节点
	choices.push_back(root -> num);
	if(sum == k){
		for(int choice:choices){
			cout << choice << " ";
		}
		cout << endl;
	}
	DFS(root -> lchild, true, sum, choices, k);
	DFS(root -> rchild, true, sum, choices, k);
	choices.pop_back();
}

int main(){
	int k, num;
	Node *root = NULL, *fa=NULL;
	queue<Node*> que;
	cin >> k;
	string input;
	while(cin >> input){
		if(input == "null"){
			num = 0x3f3f3f3f;//用于标记该节点为无效值 应生成NULL
		}else{
			stringstream ss(input);
			ss >> num;
		}
		if(root == NULL){//没有根节点则先建立根节点
			root = new Node{num, NULL, NULL};
			que.push(root);
		}else{//如果有父节点则先判断当前根节点是否已经挂好孩子,如果没有则挂孩子,否则取下一个父节点
			if(fa == NULL || fa -> have_r){//还未设置父亲(上一步刚建立根节点)或者父亲的子节点都已经满了 重新取一个 
				fa = que.front();
				que.pop();
			}
			Node* son = num == 0x3f3f3f3f ? NULL : new Node{num, NULL, NULL};
			if(son != NULL){
				que.push(son);
			}
			if(fa -> have_l == false){//如果父节点的左孩子没有挂节点,则挂节点
				fa -> lchild = son;
				fa -> have_l = true;
			}else{//否则此时应该挂右节点
				fa -> rchild = son;
				fa -> have_r = true;
			}
		}
	}
	vector<int> choices;
	DFS(root, false, 0, choices, k);
	return 0;
} 

注:本方法还不能完全去掉重复路径,因为可能存在路径节点不同但是路径上的值都相同的情况,如下

此时存在两条1-3的路径,如果题目要求不能一点重复,则可以选择使用hash_set的方式,对于路径1-3,可以进行如下方式的存储 - 1#3#,需要#作为分隔符是为了防止出现诸如值为13的节点导致路径1-3(两个节点)和路径13(一个节点)无法区分的情况。

oh...no!!!我们看丢了一个条件,节点得分=节点值+节点所在层(根节点为 0,之后每层+1)

但是我们在当前代码的基础上小改一下即可,有两种修改方式

1. 在节点建立的过程中直接增加层次

2. 在DFS的过程中增加floor表明层数

二者均可,读者请自行斟酌,本人这里简单起见用第二种

#include<bits/stdc++.h>
using namespace std; 

struct Node{
	int num;
	Node *lchild, *rchild;
	bool have_l = false, have_r = false; //由于我们没有办法通过lchild、rchild是否为null判断是否有孩子,所以需要手动设置标记位
	Node(int num, Node *lchild, Node *rchild){
		this -> num = num;
		this -> lchild = lchild;
		this -> rchild = rchild;
	}
};

void DFS(Node* root, bool start, int sum, vector<int>& choices, int floor, int k){
	if(!root){
		return;
	}
	if(!start){//如果路径还没开始,则当前节点可以选择不加入
		DFS(root -> lchild, false, 0, choices, floor + 1, k);
		DFS(root -> rchild, false, 0, choices, floor + 1, k);
	}
	sum = sum + root ->num + floor;//累计上当前节点
	choices.push_back(root -> num);
	if(sum == k){
		for(int choice:choices){
			cout << choice << " ";
		}
		cout << endl;
	}
	DFS(root -> lchild, true, sum, choices, floor + 1, k);
	DFS(root -> rchild, true, sum, choices, floor + 1, k);
	choices.pop_back();
}

int main(){
	int k, num;
	Node *root = NULL, *fa=NULL;
	queue<Node*> que;
	cin >> k;
	string input;
	while(cin >> input){
		if(input == "null"){
			num = 0x3f3f3f3f;//用于标记该节点为无效值 应生成NULL
		}else{
			stringstream ss(input);
			ss >> num;
		}
		if(root == NULL){//没有根节点则先建立根节点
			root = new Node{num, NULL, NULL};
			que.push(root);
		}else{//如果有父节点则先判断当前根节点是否已经挂好孩子,如果没有则挂孩子,否则取下一个父节点
			if(fa == NULL || fa -> have_r){//还未设置父亲(上一步刚建立根节点)或者父亲的子节点都已经满了 重新取一个 
				fa = que.front();
				que.pop();
			}
			Node* son = num == 0x3f3f3f3f ? NULL : new Node{num, NULL, NULL};
			if(son != NULL){
				que.push(son);
			}
			if(fa -> have_l == false){//如果父节点的左孩子没有挂节点,则挂节点
				fa -> lchild = son;
				fa -> have_l = true;
			}else{//否则此时应该挂右节点
				fa -> rchild = son;
				fa -> have_r = true;
			}
		}
	}
	vector<int> choices;
	DFS(root, false, 0, choices, 0, k);
	return 0;
} 

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

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

相关文章

21- 神经网络模型_超参数搜索 (TensorFlow系列) (深度学习)

知识要点 fetch_california_housing&#xff1a;加利福尼亚的房价数据&#xff0c;总计20640个样本&#xff0c;每个样本8个属性表示&#xff0c;以及房价作为target 超参数搜索的方式: 网格搜索, 随机搜索, 遗传算法搜索, 启发式搜索 函数式添加神经网络: model.add(keras.l…

Python可视化界面编程入门

Python可视化界面编程入门具体实现代码如所示&#xff1a; &#xff08;1&#xff09;普通可视化界面编程代码入门&#xff1a; import sys from PyQt5.QtWidgets import QWidget,QApplication #导入两个类来进行程序界面编程if __name__"__main__":#创建一个Appl…

探索ChatGPT背后的网络基础设施

ChatGPT是OpenAI公司开发的一款聊天机器人应用&#xff0c;自2022年11月推出以来以迅雷不及掩耳盗铃之势火爆全球。ChatGPT不仅可以模仿人类对话&#xff0c;还可以创建音乐、电视剧、童话故事和学生论文&#xff0c;甚至是编写和调试计算机程序。 截至2023年1月&#xff0c;C…

如何打造自己的小程序生态?

2021 年全网小程序数量就已超 700 万&#xff0c;从微信开始&#xff0c;到其他各大平台&#xff0c;如抖音、支付宝&#xff0c;小程序发展迅猛&#xff0c;2023年小程序仍有着巨大的发展潜力。 现在。人们逐渐发现&#xff0c;日常的生活、出行、购物各个方面都越来越离不开…

CAN工具-VSpy(ValueCAN) - Panel面板

在介绍CANoe工具的时候&#xff0c;有介绍过Panel面板的使用&#xff0c;同样&#xff0c;在VSpy软件工具中&#xff0c;也有同类型的工具可供使用 - Graphical Panels&#xff0c;同样也能提供一个控制面板&#xff0c;然后我们通过连接信号实现不同的控件&#xff0c;已达到我…

极验4参数分析

目标链接 aHR0cHM6Ly9ndDQuZ2VldGVzdC5jb20v接口分析 开发者人员工具进行抓包&#xff0c;刷新页面&#xff0c;抓到了一个名为 load?captcha_idxxx 的包&#xff0c;Query String Parameters 包含了一些参数 captcha_id&#xff1a;验证码 id&#xff0c;固定值&#xff0c…

如何使用AzureGraph通过Microsoft Graph收集Azure活动目录信息

关于AzureGraph AzureGraph是一款针对Azure活动目录的信息收集工具&#xff0c;该工具基于Microsoft Graph实现其功能。多亏了Microsoft Graph技术&#xff0c;AzureGraph才能从Azure活动目录获取各种信息&#xff0c;如用户、设备、应用程序、域等。 此应用程序允许我们通过…

一次性搞定 `SHOW SLAVE STATUS` 的解读

一次性搞定 SHOW SLAVE STATUS 的解读 解析日志文件的位置 诚然, GTID(全局事务标识符)已经在 MySQL 5.6中得到支持, 此外,还可以通过 Tungsten replicator 软件来实现(2009年以后一直有谷歌在维护,不是吗?)。 但有一部分人还在使用MySQL 5.5的标准副本方式, 那么这些二进制日…

20道经典自动化测试面试题

概述 觉得自动化测试很难&#xff1f; 是的&#xff0c;它确实不简单。但是学会它&#xff0c;工资高啊&#xff01; 担心面试的时候被问到自动化测试&#xff1f; 嗯&#xff0c;你担心的没错&#xff01;确实会被经常问到&#xff01; 现在应聘软件测试工程师的岗位&…

前端经典react面试题及答案

为什么 React 元素有一个 $$typeof 属性 目的是为了防止 XSS 攻击。因为 Synbol 无法被序列化&#xff0c;所以 React 可以通过有没有 $$typeof 属性来断出当前的 element 对象是从数据库来的还是自己生成的。 如果没有 $$typeof 这个属性&#xff0c;react 会拒绝处理该元素。…

docker搭建redis集群模式

目录docker 安装redis1.创建redis.conf开启redis验证(开启密码)允许redis外地连接后台启动开启redis持久化2.启动redis容器3.进入容器redis集群3主3从1.新建6个redis容器2.构建主从关系3.查询集群信息4.主从扩容5.主从缩容docker 安装redis 1.创建redis.conf 开启redis验证(开…

第四阶段-12关于Spring Security框架,RBAC,密码加密原则

关于csmall-passport项目 此项目主要用于实现“管理员”账号的后台管理功能&#xff0c;主要实现&#xff1a; 管理员登录添加管理员删除管理员显示管理员列表启用 / 禁用管理员 关于RBAC RBAC&#xff1a;Role-Based Access Control&#xff0c;基于角色的访问控制 在涉及…

Feign Ribbon Hystrix 三者关系

在微服务架构的应用中&#xff0c; Feign、Hystrix&#xff0c;Ribbon 三者都是必不可少的&#xff0c;可以说已经成为铁三角。 Feign 介绍 Feign 是一款Java语言编写的 HttpClient 绑定器&#xff0c;在 Spring Cloud 微服务中用于实现微服务之间的声明式调用。Feign 可以定…

IIC子系统

文章目录引言一、I2C 总线驱动框架二、I2C驱动框图(重点)三、I2C 子系统软件框架3.1 I2C子系统的4个关键结构体3.2 I2C总线与平台总线的结合3.3 在设备树信息添加i2c从设备3.4 新增加i2c从设备四、i2c driver驱动的编写4.1 陀螺仪和加速度工作原理4.2 mpu6050的寄存器信息和设置…

Synchronized的锁升级过程

Synchronized的锁升级过程 synchronized锁升级过程&#xff1a;在synchronized中引入了偏向锁、轻量级锁、重量级锁之后&#xff0c;当前具体使用的是synchronzed中的那种类型锁&#xff0c;是根据线程竞争激烈程度来决定的。 偏向锁&#xff1a;在锁对象的对象头中记录一下当…

中间件之Kafka实用篇

目录标题一、一些定义&#xff08;一&#xff09;设计kafka的初衷&#xff08;二&#xff09;消息的持久化&#xff08;三&#xff09;sendfile 技术&#xff08;零拷贝&#xff09;二、获取kafka三、卡夫卡客户端工具四、kafka核心API&#xff08;功能&#xff09;五、spring …

阶段十:总结专题(第三章:虚拟机篇)

阶段十&#xff1a;总结专题&#xff08;第三章&#xff1a;虚拟机篇&#xff09;Day-第三章&#xff1a;虚拟机篇1. JVM 内存结构2. JVM 内存参数3. JVM 垃圾回收4. 内存溢出5. 类加载6. 四种引用7. finalizeDay-第三章&#xff1a;虚拟机篇 1. JVM 内存结构 要求 掌握 JVM…

Spring Cloud Alibaba全家桶(三)——微服务负载均衡器Ribbon与LoadBalancer

前言 本文为 微服务负载均衡器Ribbon与LoadBalancer 相关知识&#xff0c;下边将对什么是Ribbon&#xff08;包括&#xff1a;客户端的负载均衡、服务端的负载均衡、常见负载均衡算法&#xff09;&#xff0c;Nacos使用Ribbon&#xff0c;Ribbon内核原理&#xff08;包括&#…

Qt::QOpenGLWidget 渲染天空壳

在qt窗口中嵌入opengl渲染天空壳和各种立方体一 学前知识天空壳的渲染学前小知识1 立方体贴图 天空壳的渲染就是利用立方体贴图来实现渲染流程2 基础光照 光照模型3 opengl帧缓冲 如何自定义帧缓冲实现后期特效4 glsl常见的shader内置函数 glsl编程常用的内置函数二 shader代码…

部署运行ai智障写作记录【ChatRWKV】

文章目录前言一、环境安装1.python环境&#xff1a;Python 3.10。2.安装一些 pip 库numpy 、tokenizers 、prompt_toolkit3.安装pytorch 1.13.1CUDA 11.7二、运行记录1、下载代码2、下载训练参数3、编辑代码运行总结前言 看到知乎一篇教程&#xff0c; 大佬自己弄得ai小说续写…