【深度优先搜索】【树】【C++算法】2003. 每棵子树内缺失的最小基因值

news2024/11/18 21:53:18

作者推荐

动态规划的时间复杂度优化

本文涉及知识点

深度优先搜索

LeetCode2003. 每棵子树内缺失的最小基因值

有一棵根节点为 0 的 家族树 ,总共包含 n 个节点,节点编号为 0 到 n - 1 。给你一个下标从 0 开始的整数数组 parents ,其中 parents[i] 是节点 i 的父节点。由于节点 0 是 根 ,所以 parents[0] == -1 。
总共有 105 个基因值,每个基因值都用 闭区间 [1, 105] 中的一个整数表示。给你一个下标从 0 开始的整数数组 nums ,其中 nums[i] 是节点 i 的基因值,且基因值 互不相同 。
请你返回一个数组 ans ,长度为 n ,其中 ans[i] 是以节点 i 为根的子树内 缺失 的 最小 基因值。
节点 x 为根的 子树 包含节点 x 和它所有的 后代 节点。
示例 1:
在这里插入图片描述

输入:parents = [-1,0,0,2], nums = [1,2,3,4]
输出:[5,1,1,1]
解释:每个子树答案计算结果如下:

  • 0:子树包含节点 [0,1,2,3] ,基因值分别为 [1,2,3,4] 。5 是缺失的最小基因值。
  • 1:子树只包含节点 1 ,基因值为 2 。1 是缺失的最小基因值。
  • 2:子树包含节点 [2,3] ,基因值分别为 [3,4] 。1 是缺失的最小基因值。
  • 3:子树只包含节点 3 ,基因值为 4 。1是缺失的最小基因值。
    示例 2:
    在这里插入图片描述

输入:parents = [-1,0,1,0,3,3], nums = [5,4,6,2,1,3]
输出:[7,1,1,4,2,1]
解释:每个子树答案计算结果如下:

  • 0:子树内包含节点 [0,1,2,3,4,5] ,基因值分别为 [5,4,6,2,1,3] 。7 是缺失的最小基因值。
  • 1:子树内包含节点 [1,2] ,基因值分别为 [4,6] 。 1 是缺失的最小基因值。
  • 2:子树内只包含节点 2 ,基因值为 6 。1 是缺失的最小基因值。
  • 3:子树内包含节点 [3,4,5] ,基因值分别为 [2,1,3] 。4 是缺失的最小基因值。
  • 4:子树内只包含节点 4 ,基因值为 1 。2 是缺失的最小基因值。
  • 5:子树内只包含节点 5 ,基因值为 3 。1 是缺失的最小基因值。
    示例 3:

输入:parents = [-1,2,3,0,2,4,1], nums = [2,3,4,5,6,7,8]
输出:[1,1,1,1,1,1,1]
解释:所有子树都缺失基因值 1 。

提示:
n == parents.length == nums.length
2 <= n <= 105
对于 i != 0 ,满足 0 <= parents[i] <= n - 1
parents[0] == -1
parents 表示一棵合法的树。
1 <= nums[i] <= 105
nums[i] 互不相同。

深度优先搜索

除了基因1的节点及它的祖先,其它节点都缺少1。
DFS(cur)结束时,处理了且只处理了它哥哥及自己的后代,如果我们将基因1及其祖先调整成长子。可以将空间复杂从O(nlogn)降低到O(n)。
注意:如果不优化,空间复杂度是O(nn),就是直接为每个节点分配空间,复制所有的后代。极端情况下,独子树的空间复杂度是O(nn)。直接用子树的空间,独子树空间复杂度O(n);非独子树O(nlong)。

超时代码

class CParentToNeiBo
{
public:
	CParentToNeiBo(const vector<int>& parents)
	{
		m_vNeiBo.resize(parents.size());
		for (int i = 0; i < parents.size(); i++)
		{
			if (-1 == parents[i])
			{
				m_root = i;
			}
			else
			{
				m_vNeiBo[parents[i]].emplace_back(i);
			}
		}
	}
	vector<vector<int>> m_vNeiBo;
	int m_root=-1;
};

class Solution {
public:
	vector<int> smallestMissingValueSubtree(vector<int>& parents, vector<int>& nums) {
		CParentToNeiBo neiBo(parents);
		m_nums = nums;
		m_vIs1.resize(nums.size());
		m_ans.assign(nums.size(),1);
		m_vHas.resize(100'000+10);
		DFS1(neiBo.m_root, neiBo.m_vNeiBo);
		for (auto& v : neiBo.m_vNeiBo)
		{
			for (int j = 1; j < v.size(); j++)
			{
				if (m_vIs1[v[j]])
				{
					std::swap(v[0], v[j]);
				}
			}
		}
		DFS2(neiBo.m_root, neiBo.m_vNeiBo);
		return m_ans;
	}
	void DFS2(int cur, vector<vector<int>>& neiBo)
	{		
		for (const auto& next : neiBo[cur])
		{
			DFS2(next, neiBo);
		}
		m_vHas[m_nums[cur]] = true;
		while (m_vHas[m_iNeed])
		{
			m_iNeed++;
		}
		if (m_vIs1[cur])
		{
			m_ans[cur] = m_iNeed;
		}
	}
	bool DFS1(int cur, vector<vector<int>>& neiBo)
	{
		bool b = (1 == m_nums[cur]);		
		for (const auto& next : neiBo[cur])
		{
			b |= DFS1(next, neiBo);
		}
		return m_vIs1[cur]=b;
	}
	vector<int> m_nums,m_ans;
	vector<bool> m_vIs1;
	int m_iNeed = 1;
	vector<bool> m_vHas;
};

1及其祖先不用DFS

class CParentToNeiBo
{
public:
	CParentToNeiBo(const vector<int>& parents)
	{
		m_vNeiBo.resize(parents.size());
		for (int i = 0; i < parents.size(); i++)
		{
			if (-1 == parents[i])
			{
				m_root = i;
			}
			else
			{
				m_vNeiBo[parents[i]].emplace_back(i);
			}
		}
	}
	vector<vector<int>> m_vNeiBo;
	int m_root=-1;
};

class Solution {
public:
	vector<int> smallestMissingValueSubtree(vector<int>& parents, vector<int>& nums) {
		CParentToNeiBo neiBo(parents);
		m_nums = nums;
		m_vIs1.resize(nums.size());
		m_ans.assign(nums.size(),1);
		m_vHas.resize(100'000+10);
		int i1 = std::find(nums.begin(), nums.end(), 1)- nums.begin();
		while ((-1 != i1) && (nums.size() != i1))
		{
			m_vIs1[i1] = true;
			i1 = parents[i1];
		}
		for (auto& v : neiBo.m_vNeiBo)
		{
			for (int j = 1; j < v.size(); j++)
			{
				if (m_vIs1[v[j]])
				{
					std::swap(v[0], v[j]);
				}
			}
		}
		DFS2(neiBo.m_root, neiBo.m_vNeiBo);
		return m_ans;
	}
	void DFS2(int cur, vector<vector<int>>& neiBo)
	{		
		for (const auto& next : neiBo[cur])
		{
			DFS2(next, neiBo);
		}
		m_vHas[m_nums[cur]] = true;		
		if (m_vIs1[cur])
		{
            while (m_vHas[m_iNeed])
		{
			m_iNeed++;
		}
			m_ans[cur] = m_iNeed;
		}
	}
	vector<int> m_nums,m_ans;
	vector<bool> m_vIs1;
	int m_iNeed = 1;
	vector<bool> m_vHas;
};

测试用例


template<class T,class T2>
void Assert(const T& t1, const T2& t2)
{
	assert(t1 == t2);
}

template<class T>
void Assert(const vector<T>& v1, const vector<T>& v2)
{
	if (v1.size() != v2.size())
	{
		assert(false);
		return;
	}
	for (int i = 0; i < v1.size(); i++)
	{
		Assert(v1[i], v2[i]);
	}

}

int main()
{
	vector<int> parents,  nums;
	{
		Solution sln;
		parents = { -1, 0, 0, 2 }, nums = { 1, 2, 3, 4 };
		auto res = sln.smallestMissingValueSubtree(parents, nums);
		Assert({ 5,1,1,1 }, res);
	}
	
	{
		Solution sln;
		parents = { -1, 0, 1, 0, 3, 3 }, nums = { 5, 4, 6, 2, 1, 3 };
		auto res = sln.smallestMissingValueSubtree(parents, nums);
		Assert({ 7,1,1,4,2,1 }, res);
	}

	{
		Solution sln;
		parents = { -1, 2, 3, 0, 2, 4, 1 }, nums = { 2, 3, 4, 5, 6, 7, 8 };
		auto res = sln.smallestMissingValueSubtree(parents, nums);
		Assert({ 1,1,1,1,1,1,1 }, res);
	}
}

2023年2月版(当时能过)

class Solution {
public:
vector smallestMissingValueSubtree(const vector& parents, const vector& nums) {
m_c = nums.size();
m_vDirect.resize(m_c);
for (int i = 1; i < parents.size(); i++)
{
m_vDirect[parents[i]].push_back(i);
}
m_vVisiteValue.resize(m_c + 1);
m_vRet.assign(m_c, 1);
for (int i = 0; i < nums.size(); i++)
{
if (1 == nums[i])
{
DFS(i, -1,parents, nums);
break;
}
}
return m_vRet;
}
void DFS(int iCur, int iFromChild,const vector& parents, const vector& nums)
{
if (-1 == iCur)
{
return;
}
DFSForValue(iCur, iFromChild, nums);
int iMiss = (-1 == iFromChild) ? 1 : m_vRet[iFromChild];
while ((iMiss < m_vVisiteValue.size()) && (m_vVisiteValue[iMiss]))
{
iMiss++;
}
m_vRet[iCur] = iMiss;
DFS(parents[iCur], iCur, parents, nums);
}
void DFSForValue(int iCur, int iFromChild, const vector& nums)
{
m_vVisiteValue[nums[iCur]] = true;
for (auto& next : m_vDirect[iCur])
{
if (next == iFromChild)
{
continue;
}
DFSForValue(next, iFromChild, nums);
}
}
int m_c;
vector<vector> m_vDirect;
vector m_vRet;
vector m_vVisiteValue;
};

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关下载

想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版
https://download.csdn.net/download/he_zhidan/88348653

我想对大家说的话
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。

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

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

相关文章

AI Earth数据集——中国10米地物分类数据集(AIEC)

AIEarth中国10米地物分类数据集(AIEC) 简介与Notebook示例 达摩院AI Earth团队自研的中国区10m分辨率地物分类产品&#xff0c;数据包含2020-2022年中国逐年土地覆盖信息。研究团队利用Sentinel-2 数据集&#xff0c;借助深度学习方法&#xff0c;融合了多时序、多模态、Low L…

2024真正有效的苹果mac电脑清理工具CleanMyMac X

一、前言 对于Mac用户来说&#xff0c;电脑卡顿、运行缓慢无疑是一件令人头疼的事情。而市面上的清理软件又五花八门&#xff0c;效果参差不齐&#xff0c;如何才能找到一款真正有效的清理工具呢&#xff1f;今天&#xff0c;我们为大家推荐一款实力派电脑清理软件——CleanMy…

Tomcat基础及与Nginx实现动静分离,搭建高效稳定的个人博客系统

目录 引言 一、TOMCAT基础功能 &#xff08;一&#xff09;自动解压war包 &#xff08;二&#xff09;状态页 1.登录状态页 2.远程登录 &#xff08;三&#xff09;服务管理界面 &#xff08;四&#xff09;Host虚拟主机 1.设置虚拟主机 2.建立站点目录与文件 二、实…

Github配置SSH免密认证

以Ubuntu Server为例 生成SSH ssh-keygen -t ed25519 -C "your_emailexample.com" 如果系统不支持Ed25519算法&#xff0c;使用旧的命令&#xff1a; ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" 根据提示生成公私钥文件&#xff0c;记下位置…

ABAP - SALV教程05 添加页眉和页脚

先看看效果叭CL_SALV_TABLE提供了SET_TOP_OF_LIST方法设置页眉显示和SET_TOP_OF_LIST_PRINT方法设置页眉打印来实现添加页眉的目的。CL_SALV_TABLE提供了SET_END_OF_LIST方法设置页脚显示和SET_END_OF_LIST_PRINT方法设置页脚打印来实现添加页脚的目的。这个四个方法的传入参数…

mitmproxy代理

文章目录 mitmproxy1. 网络代理2. 安装3. Https请求3.1 启动mitmproxy3.2 获取证书3.3 配置代理3.4 运行测试 4. 请求4.1 读取请求4.2 修改请求4.3 拦截请求 5. 响应5.1 读取响应5.2 修改响应 6. 案例&#xff1a;共享账号6.1 登录bilibili获取cookies6.2 在代理请求中设置cook…

车灯修复UV胶的优缺点有哪些?

车灯修复UV胶的优点如下&#xff1a; 优点&#xff1a; 快速固化&#xff1a;通过紫外光照射&#xff0c;UV胶可以在5-15秒内迅速固化&#xff0c;提高了修复效率。高度透明&#xff1a;固化后透光率高&#xff0c;几乎与原始车灯材料无法区分&#xff0c;修复后车灯外观更加…

unity 数学 如何计算线和平面的交点

已知一个平面上的一点P0和法向量n&#xff0c;一条直线上的点L0和方向L,求该直线与该平面的交点P 如下图 首先我们要知道向量归一化点乘之后得到就是两个向量的夹角的余弦值&#xff0c;如果两个向量相互垂直则值是0&#xff0c;小于0则两个向量的夹角大于90度&#xff0c;大于…

Vue+SpringBoot打造便利店仓库物资信息管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 系统登陆模块2.2 便利店管理员模块2.3 菜单权限模块2.4 商品管理模块2.5 商品进货模块2.6 商品出库模块 三、系统设计3.1 总体设计3.2 可行性分析3.2.1 对现有系统的分析3.2.2 技术的可行性分析3.2.3 社会因素的分析 四…

第一篇【传奇开心果系列】Python的自动化办公库技术点案例示例:深度解读Pandas库

传奇开心果博文系列 系列博文目录Python的自动化办公库技术点案例示例系列 博文目录前言一、主要特点和功能介绍二、Series 示例代码三、DataFrame示例代码四、数据导入/导出示例代码五、数据清洗示例代码六、数据选择和过滤示例代码七、数据合并和连接示例代码八、数据分组和聚…

网络编程(IP、端口、协议、UDP、TCP)【详解】

目录 1.什么是网络编程&#xff1f; 2.基本的通信架构 3.网络通信三要素 4.UDP通信-快速入门 5.UDP通信-多发多收 6.TCP通信-快速入门 7.TCP通信-多发多收 8.TCP通信-同时接收多个客户端 9.TCP通信-综合案例 1.什么是网络编程&#xff1f; 网络编程是可以让设…

Tomcat负载均衡、动静分离

目录 引言 实验图解 1.实验环境搭建 2.部署Nginx服务器及配置静态页面Web服务 3.部署Tomcat服务及配置动态页面Web服务 4.实验验收 动态页面 静态页面 引言 tomcat服务既可以处理动态页面&#xff0c;也可以处理静态页面&#xff1b;但其处理静态页面的速度远远不如…

【解决方案】ArcGIS Engine二次开发时,运行后出现“正尝试在 OS 加载程序锁内执行托管代码。不要尝试在 DllMain...”

我们在做ArcGIS Engine二次开发时&#xff0c;特别是新手&#xff0c;安装好了开发环境&#xff0c;满怀信心的准备将按照教程搭建好的框架在Visual Studio中进行运行。点击运行后&#xff0c;却出现了“正尝试在 OS 加载程序锁内执行托管代码。不要尝试在 DllMain 或映像初始化…

猫耳语音下载(mediadown)

猫耳语音下载(mediadown) 一、介绍 猫耳语音下载,能够帮助你下载猫耳音频节目。如果你是会员,它还能帮你下载会员节目。 二、下载地址 下载:猫耳语音下载(mediadown) 百度网盘下载:猫耳语音下载(mediadown) 三、安装教程 将下载的文件解压到D:\xibinhui,D:\Pr…

数据结构 - Trie树(字符串统计、最大异或对)

文章目录 前言Part 1&#xff1a;Trie字符串统计1.题目描述输入格式输出格式数据范围输入样例输出样例 2.算法 Part 2&#xff1a;最大异或对1.题目描述输入格式输出格式数据范围输入样例输出样例 2.算法 前言 本篇博客将介绍Trie树的常见应用&#xff0c;包括&#xff1a;Trie…

服务器硬件基础知识

1. 服务器分类 服务器分类 服务器的分类没有一个统一的标准。 从多个多个维度来看服务器的分类可以加深我们对各种服务器的认识。 N.B. CISC: complex instruction set computing 复杂指令集计算 RISC: reduced instruction set computer 精简指令集计算 EPIC: explicitly p…

flurl升级之后没有FlurlNewtonsoftJsonSerializer

新建NewtonsoftJsonSerializer.cs /// <summary> /// ISerializer implementation based on Newtonsoft.Json. /// Default serializer used in calls to GetJsonAsync, PostJsonAsync, etc. /// </summary> public class NewtonsoftJsonSerializer : IJsonSerial…

Project_Euler-45 题解

Project_Euler-45 题解 题目 思路 非常简单&#xff0c;枚举六边形数字&#xff0c;然后判断他们是不是三角形和五边形数&#xff0c;如果是&#xff0c;那么输出。 代码 #include <stdio.h> #include <stdlib.h> #include <math.h> #include <string.…

【详识JAVA语言】逻辑控制

概述 我的曾经&#xff1a; 早上8:00起床--->洗漱--->吃早饭--->上课--->吃午饭--->上课--->运动--->吃完饭--->玩手机--->睡觉 每天的生活貌似都是这么规律&#xff0c;顺序的做着每件事&#xff0c;前途一片渺茫~~~ 直到有一天&#xff1a; 我…