【图论】【拓扑排序】1857. 有向图中最大颜色值

本文涉及的知识点

图论 拓扑排序

LeetCode1857. 有向图中最大颜色值

给你一个 有向图 ,它含有 n 个节点和 m 条边。节点编号从 0 到 n - 1 。
给你一个字符串 colors ,其中 colors[i] 是小写英文字母,表示图中第 i 个节点的 颜色 (下标从 0 开始)。同时给你一个二维数组 edges ,其中 edges[j] = [aj, bj] 表示从节点 aj 到节点 bj 有一条 有向边 。
图中一条有效 路径 是一个点序列 x1 -> x2 -> x3 -> … -> xk ,对于所有 1 <= i < k ,从 xi 到 xi+1 在图中有一条有向边。路径的 颜色值 是路径中 出现次数最多 颜色的节点数目。
请你返回给定图中有效路径里面的 最大颜色值 。如果图中含有环,请返回 -1 。

示例 1:

在这里插入图片描述

输入:colors = “abaca”, edges = [[0,1],[0,2],[2,3],[3,4]]
输出:3
解释:路径 0 -> 2 -> 3 -> 4 含有 3 个颜色为 “a” 的节点(上图中的红色节点)。
示例 2:

在这里插入图片描述

输入:colors = “a”, edges = [[0,0]]
输出:-1
解释:从 0 到 0 有一个环。

提示:

n == colors.length
m == edges.length
1 <= n <= 105
0 <= m <= 105
colors 只含有小写英文字母。
0 <= aj, bj < n

拓扑排序

建立后邻接表后,直接调用拓扑排序的封装类。
拓扑排序保证排除已经处理节点后,当前节点的出度为0。也就是当前 节点 能够到达的节点都已经处理。这保证无后效性。
每个节点。
如果拓扑排序没有处理完所有节点,说明有环。
m_vLen[cur][i] 表示以cur开始的路径中最多有多少个’a’+i。
时间复杂度: 每个节点最多处理一次,每次处理,处理它所有的临接表。故时间复杂度:O(E)。E是边数。

代码

class CNeiBo
{
public:	
	static vector<vector<int>> Two(int n, vector<vector<int>>& edges, bool bDirect, int iBase = 0) 
	{
		vector<vector<int>>  vNeiBo(n);
		for (const auto& v : edges)
		{
			vNeiBo[v[0] - iBase].emplace_back(v[1] - iBase);
			if (!bDirect)
			{
				vNeiBo[v[1] - iBase].emplace_back(v[0] - iBase);
			}
		}
		return vNeiBo;
	}	
	static vector<vector<std::pair<int, int>>> Three(int n, vector<vector<int>>& edges, bool bDirect, int iBase = 0)
	{
		vector<vector<std::pair<int, int>>> vNeiBo(n);
		for (const auto& v : edges)
		{
			vNeiBo[v[0] - iBase].emplace_back(v[1] - iBase, v[2]);
			if (!bDirect)
			{
				vNeiBo[v[1] - iBase].emplace_back(v[0] - iBase, v[2]);
			}
		}
		return vNeiBo;
	}
	static vector<vector<int>> Grid(int rCount, int cCount, std::function<bool(int, int)> funVilidCur, std::function<bool(int, int)> funVilidNext)
	{
		vector<vector<int>> vNeiBo(rCount * cCount);
		auto Move = [&](int preR, int preC, int r, int c)
		{
			if ((r < 0) || (r >= rCount))
			{
				return;
			}
			if ((c < 0) || (c >= cCount))

			{
				return;
			}
			if (funVilidCur(preR, preC) && funVilidNext(r, c))
			{
				vNeiBo[cCount * preR + preC].emplace_back(r * cCount + c);
			}
		};

		for (int r = 0; r < rCount; r++)
		{
			for (int c = 0; c < cCount; c++)
			{
				Move(r, c, r + 1, c);
				Move(r, c, r - 1, c);
				Move(r, c, r, c + 1);
				Move(r, c, r, c - 1);
			}
		}
		return vNeiBo;
	}
	static vector<vector<int>> Mat(vector<vector<int>>& neiBoMat)
	{
		vector<vector<int>> neiBo(neiBoMat.size());
		for (int i = 0; i < neiBoMat.size(); i++)
		{
			for (int j = i + 1; j < neiBoMat.size(); j++)
			{
				if (neiBoMat[i][j])
				{
					neiBo[i].emplace_back(j);
					neiBo[j].emplace_back(i);
				}
			}
		}
		return neiBo;
	}
};

class CTopSort
{
public:	
	void Init(const vector<vector<int>>& vNeiBo)
	{
		m_c = vNeiBo.size();
		m_vBackNeiBo.resize(m_c);
		vector<int> vOutDeg(m_c);
		for (int cur = 0; cur < m_c; cur++)
		{
			vOutDeg[cur] = vNeiBo[cur].size();	
			for (const auto& next : vNeiBo[cur])
			{
				m_vBackNeiBo[next].emplace_back(cur);
			}
		}
		queue<int> que;
		for (int i = 0; i < m_c; i++)
		{
			if (0 == vOutDeg[i])
			{
				que.emplace(i);
				m_vLeaf.emplace_back(i);
				OnDo(-1, i);
			}
		}

		while (que.size())
		{
			const int cur = que.front();
			que.pop();
			for (const auto& next : m_vBackNeiBo[cur])
			{
				vOutDeg[next]--;
				if (0 == vOutDeg[next])
				{
					que.emplace(next);
					OnDo(cur, next);
				}
			}
		};
	}
	int m_c;
	vector<int> m_vLeaf;
protected:
	virtual void OnDo(int pre, int cur) = 0;
	vector<vector<int>> m_vBackNeiBo;
};

class CMyTopSort : public CTopSort
{
public:
	int Do(string& str, vector<vector<int>>& edges)
	{
		m_str = str;
		m_vLen.assign(str.length(), vector<int>(26));
		m_vNeiBo = CNeiBo::Two(str.length(),edges,true);
		CTopSort::Init(m_vNeiBo);
		if (m_iHasDo < m_c)
		{
			return -1;
		}
		int iMax = 0;
		for (const auto& v : m_vLen)
		{
			iMax = max(iMax, *std::max_element(v.begin(), v.end()));
		}
		return iMax;
	}
	vector<vector<int>> m_vLen;
protected:
	// 通过 CTopSort 继承
	virtual void OnDo(int pre, int cur) override
	{
		m_iHasDo++;
		for (int i = 0; i < 26; i++)
		{
			m_vLen[cur][i] = ('a' + i == m_str[cur]);
			int iMax = 0;
			for (const auto& next : m_vNeiBo[cur])
			{
				iMax = max(iMax, m_vLen[next][i]);
			}
			m_vLen[cur][i] += iMax;
		}
	}
	vector<vector<int>> m_vNeiBo;
	string m_str;	
	int m_iHasDo = 0;
};
class Solution {
public:
	int largestPathValue(string colors, vector<vector<int>>& edges) {
		CMyTopSort top;
		return top.Do(colors, edges);
	}
};

测试用例

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()
{
	string colors;
	vector<vector<int>> edges;

	{
		Solution sln;
		colors = "abaca", edges = { {0,1},{0,2},{2,3},{3,4} };
		auto res = sln.largestPathValue(colors, edges);
		Assert(3, res);
	}


	{
		Solution sln;
		colors = "a", edges = { {0,0} };
		auto res = sln.largestPathValue(colors, edges);
		Assert(-1, res);
	}
}

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步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++**实现。

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

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

相关文章

【深耕 Python】Data Science with Python 数据科学(7)书352页练习题

写在前面 关于数据科学环境的建立&#xff0c;可以参考我的博客&#xff1a; 【深耕 Python】Data Science with Python 数据科学&#xff08;1&#xff09;环境搭建 往期数据科学博文&#xff1a; 【深耕 Python】Data Science with Python 数据科学&#xff08;2&#xf…

鸿蒙实战开发-如何实现多设备自适应服务卡片

​介绍 本示例展示Js工程中服务卡片的布局和使用&#xff0c;其中卡片内容显示使用了一次开发&#xff0c;多端部署的能力实现多设备自适应。用到了卡片扩展模块接口&#xff0c;ohos.app.form.FormExtensionAbility 。 卡片信息和状态等相关类型和枚举接口&#xff0c;ohos.…

避雷!新增5本SCI被标记On Hold!1区、CCF推荐上榜

毕业推荐 SSCI • 社科类&#xff0c;分区稳步上升&#xff08;最快13天录用&#xff09; IEEE&#xff1a; • 计算机类&#xff0c;1区(TOP)&#xff0c;CCF推荐 SCIE • 计算机工程类&#xff0c;CCF推荐&#xff08;最快16天录用&#xff09; 期刊动态 科睿唯安新增5…

再谈数据中心网络传输

我在 大历史下的 pacing 中误会程序员了&#xff0c;程序员的路子是正确的(虽然并不指网络方面)。本文接着扯网络&#xff0c;从系统程序员熟悉的开始&#xff1a; 当 cpu 过多时&#xff0c;把大的 spinlock 拆成 percpu lock&#xff1b;使用 hash 时&#xff0c;倾向于 per…

C++之智能指针std::unique_ptr与std::make_unique分配内存方式总结(二百六十四)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

【Zblog搭建博客网站】windows环境搭建属于自己的博客并发布上线 – cpolar内网穿透

目录 1. 前言 2. Z-blog网站搭建 2.1 XAMPP环境设置 2.2 Z-blog安装 2.3 Z-blog网页测试 2.4 Cpolar安装和注册 3. 本地网页发布 3.1. Cpolar云端设置 3.2 Cpolar本地设置 4. 公网访问测试 5. 结语 1. 前言 想要成为一个合格的技术宅或程序员&#xff0c;自己搭建网…

Nacos单机版安装

1. 下载 nacos-server-2.0.3.tar.gz 官网 https://github.com/alibaba/nacos/releases 2. 上传到服务器 3. 解压 tar -zxvf nacos-server-2.0.3.tar.gz -C /opt 4. 配置数据库 4.1准备好mysql数据库 4.2创建一个新的数据库 创建新数据库nacos 4.3执行nacos建库脚本 在…

XMind 2023 下载地址及安装教程

XMind是一款流行的思维导图软件&#xff0c;它帮助用户以图形化的方式组织和呈现思维、概念和信息。XMind可以应用于各个领域&#xff0c;如项目管理、思维导图、会议记录、学习笔记等。 XMind提供了直观和易于使用的界面&#xff0c;用户可以通过拖放和连线来创建思维导图。它…

2024第16届成都学校团餐供应链展6月1日举办

2024第16届成都学校团餐供应链展6月1日举办 邀请函 主办单位&#xff1a; 中国西部教体融合博览会组委会 承办单位&#xff1a;重庆港华展览有限公司 博览会主题&#xff1a;责任教育 科教兴邦 学校团餐&#xff0c;就是老师和学生团体用餐的简称&#xff0c;也叫学校食堂…

使用Flutter混淆技术保护应用隐私与数据安全

在移动应用开发中&#xff0c;保护应用代码安全至关重要。Flutter 提供了简单易用的混淆工具&#xff0c;帮助开发者在构建 release 版本应用时有效保护代码。本文将介绍如何在 Flutter 应用中使用混淆&#xff0c;并提供了相关的操作步骤和注意事项。 &#x1f4dd; 摘要 本…

深入理解指针1:指针变量、指针运算、野指针、const修饰指针

生活中我们把门牌号也叫地址&#xff0c;在计算机中我们把内存单元的编号也称为地址。C语⾔中给地址起 了新的名字叫&#xff1a;指针。 所以我们可以理解为&#xff1a;内存单元的编号地址指针 1、指针变量 我们知道的是&#xff1a;数组名是数组首元素的地址。也就是说&…

linux离线安装NodeJs

一、官方下载 地址&#xff1a;Node.js — Download Node.js 选择linux系统版本 为了防止安装过程出现一些适配问题&#xff0c;我没有选择下载最新版&#xff0c;实际应该下载你的前端所用的nodejs版本 未完待续。。

Object 类的使用

如何理解根父类 类 java.lang.Object是类层次结构的根类&#xff0c;即所有其它类的父类。每个类都使用 Object 作为超类。 Object类型的变量与除Object以外的任意引用数据类型的对象都存在多态引用 method(Object obj){…} //可以接收任何类作为其参数 Person o new Person(…

奇趣相机AI摄影,让每个儿童成长故事都独一无二

随着科技的日新月异&#xff0c;亲子互动方式也在不断进化。近日&#xff0c;一款名为“奇趣相机”的微信小程序凭借其精准捕捉亚洲儿童特质与激发创意的独特功能&#xff0c;在年轻父母群体中引发热烈关注。这款应用程序不仅革新了儿童摄影的传统模式&#xff0c;更成为连接科…

iOS App Store审核要求与Flutter应用的兼容性分析

本文探讨了使用Flutter开发的iOS应用能否上架&#xff0c;以及上架的具体流程。苹果提供了App Store作为正式上架渠道&#xff0c;同时也有TestFlight供开发者进行内测。合规并通过审核后&#xff0c;Flutter应用可以顺利上架。但上架过程可能存在一些挑战&#xff0c;因此可能…

Node.js-知识点学习总结归纳

Node.js-知识点学习总结归纳 安装nodenode运行方式通过Node.js直接运行js文件&#xff08;也就不用通过网页html了&#xff09;绝对路径调用:相对路径调用&#xff1a;直接运行js命令&#xff1a; Vscode控制台使用node运行js文件 安装node 这个就不用讲了吧&#xff0c;网上搜…

浅谈物联网高速公路智慧配电室系统构建方案

关键词&#xff1a;高速公路&#xff1b;智慧供配电&#xff1b;电力监控&#xff1b;配电室智能运维托管&#xff1b;安全隐患 0、引言 随着高速公路事业的不断发展和路网的不断延伸&#xff0c;传统的管理方式已难以满足日益增长的需求&#xff0c;动态管理和安全隐患预警成…

使用Python绘制发散条形图案例

发散条形图用于简化多个组的比较。它的设计允许我们比较各组中的数值。它还帮助我们快速地想象出有利的和不利的或积极的和消极的反应。条形图由从中间开始的两个水平条的组合组成-一个条从右向左延伸&#xff0c;另一个从左向右延伸。条形的长度与它所代表的数值相对应。 通常…

<网络> 网络Socket 编程基于UDP协议模拟简易网络通信

目录 前言&#xff1a; 一、预备知识 &#xff08;一&#xff09;IP地址 &#xff08;二&#xff09;端口号 &#xff08;三&#xff09;端口号与进程PID &#xff08;四&#xff09;传输层协议 &#xff08;五&#xff09;网络字节序 二、socket 套接字 &#xff08;…