【深度优先搜索】【树】【状态压缩】2791. 树中可以形成回文的路径数

作者推荐

【深度优先搜索】【树】【有向图】【推荐】685. 冗余连接 II

本文涉及知识点

深度优先搜索 树 图论 状态压缩

LeetCode:2791. 树中可以形成回文的路径数

给你一棵 树(即,一个连通、无向且无环的图),根 节点为 0 ,由编号从 0 到 n - 1 的 n 个节点组成。这棵树用一个长度为 n 、下标从 0 开始的数组 parent 表示,其中 parent[i] 为节点 i 的父节点,由于节点 0 为根节点,所以 parent[0] == -1 。
另给你一个长度为 n 的字符串 s ,其中 s[i] 是分配给 i 和 parent[i] 之间的边的字符。s[0] 可以忽略。
找出满足 u < v ,且从 u 到 v 的路径上分配的字符可以 重新排列 形成 回文 的所有节点对 (u, v) ,并返回节点对的数目。
如果一个字符串正着读和反着读都相同,那么这个字符串就是一个 回文 。
示例 1:
在这里插入图片描述

输入:parent = [-1,0,0,1,1,2], s = “acaabc”
输出:8
解释:符合题目要求的节点对分别是:

  • (0,1)、(0,2)、(1,3)、(1,4) 和 (2,5) ,路径上只有一个字符,满足回文定义。
  • (2,3),路径上字符形成的字符串是 “aca” ,满足回文定义。
  • (1,5),路径上字符形成的字符串是 “cac” ,满足回文定义。
  • (3,5),路径上字符形成的字符串是 “acac” ,可以重排形成回文 “acca” 。
    示例 2:
    输入:parent = [-1,0,0,0,0], s = “aaaaa”
    输出:10
    解释:任何满足 u < v 的节点对 (u,v) 都符合题目要求。

提示:
n == parent.length == s.length
1 <= n <= 105
对于所有 i >= 1 ,0 <= parent[i] <= n - 1 均成立
parent[0] == -1
parent 表示一棵有效的树
s 仅由小写英文字母组成

深度优先搜索

树的路径一定是 起点 → \rightarrow 公共祖先 → \rightarrow 终点,特例是起点(或终点)就是公共祖先。
且从 u 到 v 的路径上分配的字符可以 重新排列 形成 回文    ⟺    \iff 各字符的数量只有1个是奇数或全部是偶数
状态压缩: mask &(1 << i ) 表示 ‘a’+i 出现的次数是奇数。

深度优先搜索的状态

暴力的办法是枚举左支和右支的状态,空间复杂度(226) 已经在超内存的边缘了。
状态优化

在这里插入图片描述
如果node1到node2的路径能构成回文,那node1 → \rightarrow root → \rightarrow node2 也能构成回文。起点(或终点)就是公共祖先 也符合。
单节点要排除,因为不符合v<v。

深度优先搜索的转移方程

vCnt[mask] 记录 各节点到root(0)的mask。
node1的压缩状态为:mask
cnt += vCnt[mask]-1
cnt += ∑ j : 0 25 v C n t [ m a s k ( 1 < < j ) ] \sum_{j:0}^{25}vCnt[mask^(1<<j)] j:025vCnt[mask(1<<j)]

深度优先搜索的返回值

cnt/2。

代码

核心代码

class Solution {
public:
	long long countPalindromePaths(vector<int>& parent, string s) {
		m_s = s; 
		vector<vector<int>> vNeiBo(parent.size());
		for (int i = 1; i < parent.size(); i++)
		{
			vNeiBo[parent[i]].emplace_back(i);
		}
		DFS(vNeiBo, 0, -1, 0);
		long long llRet = 0;
		for (const auto& [mask, cnt] : m_mMaskCount)
		{
			llRet += cnt*(cnt - 1);
			for (int j = 0; j < 26; j++)
			{
				const int iNewMask = mask ^ (1 << j);
				if (m_mMaskCount.count(iNewMask))
				{
					llRet += cnt*m_mMaskCount[iNewMask];
				}
			}
		}
		return llRet / 2;
	}
	void DFS(vector<vector<int>>& neiBo, int cur, int par, int parMask)
	{
		parMask ^= (1 << (m_s[cur]-'a'));
		m_mMaskCount[parMask]++;
		for (const auto& next : neiBo[cur])
		{
			if (next == par)
			{
				continue;
			}
			DFS(neiBo, next, cur, parMask);
		}
	}
	unordered_map<int, long long> m_mMaskCount;
	string m_s;
};

测试用例

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> parent;
	string s;
	{
		Solution sln;
		parent = { -1, 0, 0, 1, 1, 2 }, s = "acaabc";
		auto res = sln.countPalindromePaths(parent, s);
		Assert(res,8);
	}

	{
		Solution sln;
		parent = { -1, 0, 0, 0, 0 }, s = "aaaaa";
		auto res = sln.countPalindromePaths(parent, s);
		Assert(res, 10);
	}
	
}

2023年11月版

class Solution{
public:
long long countPalindromePaths(vector&parent, string s) {
m_c = parent.size();
m_str = s;
m_vNeiBo.assign(m_c, vector());
for (int i = 0; i < 26; i++)
{
m_iVilidMask[i] = 1 << i;
}
m_llRet = 0;
m_mMaskNums.clear();
int iRoot = -1;
for (int i = 0; i < m_c; i++)
{
if (-1 == parent[i])
{
iRoot = i;
}
else
{
m_vNeiBo[parent[i]].emplace_back(i);
}
}
dfs(iRoot,0);
return m_llRet;
}
void dfs(int cur,int iMask)
{
const int curMask = iMask ^ ( 1 << (m_str[cur] - ‘a’));
for (int i = 0; i < 27; i++)
{
const int iNeedMask = m_iVilidMask[i] ^ curMask;
if (m_mMaskNums.count(iNeedMask))
{
m_llRet += m_mMaskNums[iNeedMask];
}
}
m_mMaskNums[curMask]++;
for (const auto& child : m_vNeiBo[cur])
{
dfs(child, curMask);
}
}
int m_iVilidMask[27] = { 0 };//记录所有字符都是偶数和只有一个字符是奇数
vector<vector> m_vNeiBo;
std::unordered_map<int,int> m_mMaskNums;
int m_c;
long long m_llRet = 0;//不包括单节点的合法路径数
string m_str;
};

扩展阅读

视频课程

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

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

相关文章

Javascript怎么输出内容?两种常见方式以及控制台介绍

javascript是一种非常重要的编程语言&#xff0c;在许多网页中它被广泛使用&#xff0c;可以实现许多交互效果和动态效果。输出是javascript中最基本的操作之一&#xff0c;下面将介绍两种常见的输出方式。 一、使用console.log()函数输出 console.log()函数是常用的输出函数…

【牛客面试必刷TOP101】Day24.BM34 判断是不是二叉搜索树和BM35 判断是不是完全二叉树

作者简介&#xff1a;大家好&#xff0c;我是未央&#xff1b; 博客首页&#xff1a;未央.303 系列专栏&#xff1a;牛客面试必刷TOP101 每日一句&#xff1a;人的一生&#xff0c;可以有所作为的时机只有一次&#xff0c;那就是现在&#xff01;&#xff01;&#xff01;&…

3d模型导出fbx面出错是什么原因?怎么解决---模大狮模型网

3D模型在导出为FBX格式时出错可能有多种原因&#xff0c;以下是一些常见的原因和解决方法&#xff1a; 一&#xff1a;模型包含不支持的元素 某些特定的元素或功能在导出为FBX格式时可能会导致错误。例如&#xff0c;某些软件中使用了特殊的插件、约束或动画效果&#xff0c;这…

【学习笔记】数据结构与算法04:哈希表、哈希冲突、哈希算法

知识出处&#xff1a;Hello算法&#xff1a;https://www.hello-algo.com/ 文章目录 2.3 哈希表2.3.1 哈希表「 hash table」2.3.1.1 哈希表常见操作2.3.1.2 哈希表的简单实现2.3.1.3 哈希冲突与扩容 2.3.2 哈希冲突2.3.2.1 「链式地址 separate chaining」2.3.2.2 「开放寻址 o…

数字革命的先锋:探索Web3的无限可能性

随着科技的不断进步&#xff0c;我们正在迎来数字革命的新时代。在这个时代中&#xff0c;Web3技术作为数字革命的先锋&#xff0c;正以其独特的特点和无限的可能性引领着未来的发展方向。本文将深入探索Web3技术的核心原理、应用场景以及对未来的影响&#xff0c;揭示数字革命…

32看门狗

目录 一.看门狗简介 二&#xff0e;代码实现 一.看门狗简介 IWDG的专用时钟是LSI&#xff0c;内部低速时钟 WWDG使用的是APB&#xff11;的时钟&#xff0c;并没有专门的时钟&#xff0c;所以并不独立 如果独立看门狗已经由硬件选项或软件启动&#xff0c; LSI振荡器将被强制…

Aster实现一台电脑当两台使——副屏搭配键鼠

前言&#xff1a;笔者每年回家&#xff0c;都面临着想要和小伙伴一起玩游戏&#xff0c;但小伙伴没有电脑/只有低配电脑的问题。与此同时&#xff0c;笔者自身的电脑是高配置的电脑&#xff0c;因此笔者想到&#xff0c;能否在自己的电脑上运行游戏&#xff0c;在小伙伴的电脑上…

C++从入门到精通 第十二章(C++流)

一、C流的概念 1、C流的体系结构 &#xff08;1&#xff09;C为实现数据的输入输出定义了一系列的流类&#xff0c;这些类之间的派生、继承关系如下图所示&#xff0c;它们之中一部分是用模板实现的&#xff0c;图中用细线框表示&#xff0c;另外图中的虚线表示模板类与模板实…

计算机二级C语言的注意事项及相应真题-5-程序修改

目录 41.累加链表结点数据域中的数据作为函数值返回42.根据整型形参m&#xff0c;计算如下公式的值43.删除数列中值为x的元素44.从N个字符串中找出最长的那个串&#xff0c;并将其地址作为函数值返回45.将两个长度相等的纯数字字符串当作两个加数&#xff0c;求其代表的数值之和…

【Docker】Linux主机部署Docker

Docker部署 1.二进制文件部署 到如下地址&#xff0c;下载二进制包。 Docker官网&#xff1a;https://docs.docker.com/engine/install/binaries/ 网易镜像源&#xff1a;https://mirrors.163.com/docker-ce/linux/static/stable/x86_64/ 下载好的二进制包上传到主机&#xf…

C++项目 -- 高并发内存池(七)性能瓶颈与优化

C项目 – 高并发内存池&#xff08;七&#xff09;性能瓶颈与优化 文章目录 C项目 -- 高并发内存池&#xff08;七&#xff09;性能瓶颈与优化一、检测性能瓶颈二、使用基数树来优化项目1.基数树2.不加锁的原理3.性能对比 三、最终代码实现 一、检测性能瓶颈 DeBug下运行代码&…

015—pandas 标记按月连续变化趋势

前言 在业务数据分析中&#xff0c;特别是和时间相关的数据&#xff0c;会经常要判断数据的变化情况&#xff0c;比如是否是增长还是降低&#xff0c;或是持平。 需求 以数据中最后的月份为基础&#xff0c;来看它最近的数据变化&#xff0c;并将变化情况标记在本行的最后一…

网络基础与通信原理:构建数字世界的框架

目录 初识计算机网络 网络介绍 按照拓扑分类 按地域分类 网络设备 交换机&#xff08;switch&#xff09; 路由器&#xff08;router&#xff09; 传输介质 双绞线 光纤 光纤速度 ISO ISO和OSI有什么关系呢&#xff1f; OSI七层模型 TCP/IP四层 TCP/IP协议族 …

Atmel ATSHA204应用总结

1 ACES软件安装 Atmel Crypto Evaluation Studio (ACES) https://www.microchip.com/DevelopmentTools/ProductDetails/PartNO/Atmel%20Crypto%20%20Studio%20(ACES) 2 基本概念 ACES CE&#xff1a;Atmel Crypto Evalution Studio Configuration Environment&#xff08;基于加…

美国纽约时代广场纳斯达克大屏投放-大舍传媒

美国纽约时代广场纳斯达克大屏投放-大舍传媒 引言 对于大舍传媒来说&#xff0c;能够在美国纽约时代广场纳斯达克大屏投放广告是一个里程碑式的时刻。这不仅仅代表着大舍传媒在全球范围内的知名度与实力&#xff0c;也标志着该公司在国际市场上取得了巨大的进展。纽约时代广场…

Prometheus+TDengine集群实现监控体系高可用

背景 为避免再次出现因Prometheus宕机导致业务无法查看历史数据受到影响&#xff0c;准备将Prometheus架构从单节点方式升级为高可用集群方式并将后端存储由本地存储改为远端分布式时序数据库存储。分布式时序数据库采用国产数据库TDengine。 架构 解释&#xff1a;虚线代表P…

【安卓基础3】Activity(一)

&#x1f3c6;作者简介&#xff1a;|康有为| &#xff0c;大四在读&#xff0c;目前在小米安卓实习&#xff0c;毕业入职 &#x1f3c6;安卓学习资料推荐&#xff1a; 视频&#xff1a;b站搜动脑学院 视频链接 &#xff08;他们的视频后面一部分没再更新&#xff0c;看看前面也…

C#之WPF学习之路(1)

目录 WPF的起源 C的qt和C#的wpf对比 winform 和 wpf有什么区别 安装 Visual Studio2022 创建 HelloWorld 程序 App.xaml与Application类 Application的生命周期 Window窗体的生命周期 WPF的起源 WPF&#xff08;Windows Presentation Foundation&#xff09;是一种用于…

《图解设计模式》笔记(二)交给子类

三、Template Method模式&#xff1a;将具体处理交给子类 示例程序类图 public static void main(String[] args) {// 生成一个持有H的CharDisplay类的实例AbstractDisplay d1 new CharDisplay(H);// 生成一个持有"Hello, world."的StringDisplay类的实例AbstractD…

【HarmonyOS应用开发】三方库(二十)

三方库的基本使用 一、如何获取三方库 目前提供了两种途径获取开源三方库&#xff1a; 通过访问Gitee网站开源社区获取 在Gitee中&#xff0c;搜索OpenHarmony-TPC仓库&#xff0c;在tpc_resource中对三方库进行了资源汇总&#xff0c;可以供开发者参考。 通过OpenHarmony三…