【并集查找 最大公约数 调和数】952. 按公因数计算最大组件大小

news2025/6/24 13:51:52

本文涉及知识点

图论 并集查找 最大公约数 调和数

LeetCode952. 按公因数计算最大组件大小

给定一个由不同正整数的组成的非空数组 nums ,考虑下面的图:
有 nums.length 个节点,按从 nums[0] 到 nums[nums.length - 1] 标记;
只有当 nums[i] 和 nums[j] 共用一个大于 1 的公因数时,nums[i] 和 nums[j]之间才有一条边。
返回 图中最大连通组件的大小 。
示例 1:
在这里插入图片描述
输入:nums = [4,6,15,35]
输出:4
示例 2:
在这里插入图片描述
输入:nums = [20,50,9,63]
输出:2
示例 3:
在这里插入图片描述

输入:nums = [2,3,6,7,4,12,21,39]
输出:8
提示:
1 <= nums.length <= 2 * 104
1 <= nums[i] <= 105
nums 中所有值都 不同

调和数

m = max(nums[i])。
vIndex记录各数的下标:-1,非法。相同的值如果有多个,只记录第一个。重复出现的数和第一个元素连接。
枚举x$\in[1,max(nums[i])] v[x] 记录x的倍数下标。
v[x]的数据分别和v[x][0]连接。
枚举1的倍数,需要运算m次。
枚举2的倍数,需要运算m/2。
枚举3的倍数,需要运算m/3。
⋯ \cdots
总次数为:m(1+1/2+1/3 + ⋯ \cdots +1/m) ,括号内是调和数, ≈ \approx logm。
故总时间复杂度为:O(mlogm)。
v[x] 就是可以只记录一个元素,后面的元素直接和它连接。

代码

核心代码

class CUnionFind
{
public:
	CUnionFind(int iSize) :m_vNodeToRegion(iSize)
	{
		for (int i = 0; i < iSize; i++)
		{
			m_vNodeToRegion[i] = i;
		}
		m_iConnetRegionCount = iSize;
	}	
	CUnionFind(vector<vector<int>>& vNeiBo):CUnionFind(vNeiBo.size())
	{
		for (int i = 0; i < vNeiBo.size(); i++) {
			for (const auto& n : vNeiBo[i]) {
				Union(i, n);
			}
		}
	}
	int GetConnectRegionIndex(int iNode)
	{
		int& iConnectNO = m_vNodeToRegion[iNode];
		if (iNode == iConnectNO)
		{
			return iNode;
		}
		return iConnectNO = GetConnectRegionIndex(iConnectNO);
	}
	void Union(int iNode1, int iNode2)
	{
		const int iConnectNO1 = GetConnectRegionIndex(iNode1);
		const int iConnectNO2 = GetConnectRegionIndex(iNode2);
		if (iConnectNO1 == iConnectNO2)
		{
			return;
		}
		m_iConnetRegionCount--;
		if (iConnectNO1 > iConnectNO2)
		{
			UnionConnect(iConnectNO1, iConnectNO2);
		}
		else
		{
			UnionConnect(iConnectNO2, iConnectNO1);
		}
	}

	bool IsConnect(int iNode1, int iNode2)
	{
		return GetConnectRegionIndex(iNode1) == GetConnectRegionIndex(iNode2);
	}
	int GetConnetRegionCount()const
	{
		return m_iConnetRegionCount;
	}
	vector<int> GetNodeCountOfRegion()//各联通区域的节点数量
	{
		const int iNodeSize = m_vNodeToRegion.size();
		vector<int> vRet(iNodeSize);
		for (int i = 0; i < iNodeSize; i++)
		{
			vRet[GetConnectRegionIndex(i)]++;
		}
		return vRet;
	}
	std::unordered_map<int, vector<int>> GetNodeOfRegion()
	{
		std::unordered_map<int, vector<int>> ret;
		const int iNodeSize = m_vNodeToRegion.size();
		for (int i = 0; i < iNodeSize; i++)
		{
			ret[GetConnectRegionIndex(i)].emplace_back(i);
		}
		return ret;
	}
private:
	void UnionConnect(int iFrom, int iTo)
	{
		m_vNodeToRegion[iFrom] = iTo;
	}
	vector<int> m_vNodeToRegion;//各点所在联通区域的索引,本联通区域任意一点的索引,为了增加可理解性,用最小索引
	int m_iConnetRegionCount;
};

class Solution {
public:
	int largestComponentSize(vector<int>& nums) {
		m_c = nums.size();
		const int iMax = *std::max_element(nums.begin(), nums.end());
		CUnionFind uf(m_c);
		vector<int> vIndex(iMax + 1, -1);
		for (int i = 0; i < m_c; i++) {
			if (-1 == vIndex[nums[i]]) {
				vIndex[nums[i]] = i;
			}
			else
			{
				uf.Union(i, vIndex[nums[i]]);
			}
		}
		for (int x = 2; x <= iMax; x++) {
			int pre = -1;
			for (int cur = x; cur <= iMax; cur += x) {
				if (-1 == vIndex[cur]) { continue; }
				if (-1 == pre) {
					pre = vIndex[cur];
				}
				else {
					uf.Union(pre, vIndex[cur]);
				}
			}
		}
		auto m = uf.GetNodeOfRegion();
		int iRet = 0;
		for (const auto& [tmp, v] : m) {
			iRet = max(iRet, (int)v.size());
		}
		return iRet;
	}
	int m_c;
};

测试用例

template<class T>
void Assert(const T& t1, const T& 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> nums;
	{
		Solution sln;
		nums = { 20,50,9,63 };
		auto res = sln.largestComponentSize(nums);
		Assert(2, res);
	}
	{
		Solution sln;
		nums = { 4, 6, 15, 35 };
		auto res = sln.largestComponentSize(nums);
		Assert(4, res);
	}
	
	{
		Solution sln;
		nums = { 2,3,6,7,4,12,21,39 };
		auto res = sln.largestComponentSize(nums);
		Assert(8, 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++**实现。

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

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

相关文章

Git的操作和使用

一、基本操作 1、创建git本地仓库 &#xff08;1&#xff09;创建目录&#xff1a;mkdir gitcode &#xff08;2&#xff09;进入目录&#xff1a;cd gitcode/ &#xff08;3&#xff09;查询目录内容&#xff1a;ls &#xff08;4&#xff09;在当前目录下创建git本地仓库…

react引入iconfont的svg图标

react引入iconfont的svg图标 本文目录 react引入iconfont的svg图标普通图标通过link引入css组件内引入css使用 svg图标通过script引入js组件内引入js使用 通过封装组件自定义封装组件中调用 通过antd封装使用 普通图标 通过link引入css <link rel"stylesheet" h…

机器学习进行情感分析(上)

目录 一、 绪论二、 数据处理1. 构建CSV文档2. 构建模型前的思考2.1. 问题2.2. 解决方法 3. 读取数据4. 用正则表达式来进行对特定符号的剔除5. 使用口袋模型进行文本处理和特征提取 三、 数据划分 一、 绪论 近年来&#xff0c;随着互联网和社交媒体的快速发展&#xff0c;人们…

python自动化登录(测试篇)

起初是想抓取下请求看能不能做模拟登录。无奈发现&#xff0c;目标网站的请求数据是加密过的&#xff0c;而且网站代码也是编译后的代码。要从编译后的代码中提取加密算法。我的第一想法是明知不可为而不为。但是转念一想&#xff0c;何不试试python大法。 1.前期准备 python我…

Android图片压缩、Drawable和Bitmap转换、bitmap和base64转换

1. Android图片压缩、Drawable和Bitmap转换、bitmap和base64转换 1.1. Drawable和Bitmap之间的转化 1.1.1. bitmap和Drawable间的区别 Bitmap - 称作位图&#xff0c;一般位图的文件格式后缀为bmp&#xff0c;当然编码器也有很多如RGB565、RGB888。作为一种逐像素的显示对象执…

【c++】深入剖析与动手实践:C++中Stack与Queue的艺术

&#x1f525;个人主页&#xff1a;Quitecoder &#x1f525;专栏&#xff1a;c笔记仓 朋友们大家好&#xff0c;本篇文章我们来到STL新的内容&#xff0c;stack和queue 目录 1. stack的介绍与使用函数介绍例题一&#xff1a;最小栈例题二&#xff1a;栈的压入、弹出队列栈的模…

架构师系列- 消息中间件(15)-kafka业务实战

7.1 顺序性场景 7.1.1 场景概述 假设我们要传输一批订单到另一个系统&#xff0c;那么订单对应状态的演变是有顺序性要求的。 已下单 → 已支付 → 已确认 不允许错乱&#xff01; 7.1.2 顺序级别 1&#xff09;全局有序&#xff1a; 串行化。每条经过kafka的消息必须严格…

系统设计 --- E2E Test System

系统设计 --- E2E Test System 什么是E2EE2E Architecture Example 什么是E2E E2E&#xff08;端到端&#xff09;测试是一种软件测试方法&#xff0c;旨在模拟真实的用户场景&#xff0c;测试整个应用程序或系统的端到端功能和交互流程。E2E 测试涵盖了从用户界面到后端系统的…

uniapp获取当前位置及检测授权状态

uniapp获取当前位置及检测授权定位权限 文章目录 uniapp获取当前位置及检测授权定位权限效果图创建js文件permission.jslocation.js 使用 效果图 Android设备 点击 “设置”&#xff0c;跳转应用信息&#xff0c;打开“权限即可”&#xff1b; 创建js文件 permission.js 新建…

视频怎么批量压缩?5个好用的电脑软件和在线网站

视频怎么批量压缩&#xff1f;有时候我们需要批量压缩视频来节省存储空间&#xff0c;便于管理文件和空间&#xff0c;快速的传输发送给他人。有些快捷的视频压缩工具却只支持单个视频导入&#xff0c;非常影响压缩效率&#xff0c;那么今天就向大家从软件和在线网站2个角度介绍…

ProcessOn已凉,绘图就用谷歌云盘+draw.io达到了巅峰

神器draw.io 首先&#xff1a;对不起ProcessOn&#xff0c;无意冒犯&#xff0c;ProcessOn并没有凉&#xff0c;而且还一直在用。谁让你们火呢&#xff0c;借词一用&#xff0c;哈哈哈哈。 4年前我用谷歌云盘时就无意间发现了draw.io这个绘图工具。 先说下如何发现的&#x…

NumPy 1.26 中文官方指南(一)

NumPy 用户指南 原文&#xff1a;numpy.org/doc/1.26/user/index.html 本指南是一个概述&#xff0c;解释了重要特性&#xff1b;细节请参阅 NumPy 参考文档。 入门指南 什么是 NumPy? 安装 NumPy 快速入门 NumPy&#xff1a;初学者的绝对基础 基础知识和用法 NumPy 基础…

java数据结构泛型

泛型 一.了解包装类二.基本数据类型对应的包装类三.装箱与拆箱四.什么是泛型&#xff1f;五.语法六.泛型类使用七.泛型的上界八.泛型方法 在学习泛型之前,我们需要先了解一下包装类。 一.了解包装类 在Java中&#xff0c;由于基本类型不是继承自Object&#xff0c;为了在泛型代…

爬虫的实战应用之短信炸弹playwright现代网页测试工具

不讲废话&#xff0c;先上原理&#xff1a; 短信炸弹&#xff0c;也就是说持续对一个手机进行发送短信&#xff0c;实现的方式就是&#xff0c;利用某些网站的登录 &#xff0c;注册的时候&#xff0c;发送短信验证码来实现。 如下图&#xff0c;其中有一个id为phone的输入框&a…

golang beego结合wire依赖注入及自动路由

1 安装wire 1.1 通过命令直接安装 go install github.com/google/wire/cmd/wirelatest 1.2 通过go get方式安装 go get github.com/google/wire/cmd/wire进入目录编译 cd C:\Users\leell\go\pkg\mod\github.com\google\wirev0.6.0\cmd\wire go build 然后将wire.exe移动到…

代码随想录:二叉树22-24

目录 700.二叉搜索树的搜索 题目 代码&#xff08;二叉搜索树迭代&#xff09; 代码&#xff08;二叉搜索树递归&#xff09; 代码&#xff08;普通二叉树递归&#xff09; 代码&#xff08;普通二叉树迭代&#xff09; 98.验证二叉搜索树 题目 代码&#xff08;中序递…

嵌入式全栈开发学习笔记---Linux基本命令2

目录 cp 源路径 目的路径 cp -r 源路径 目的路径 mv 源路径 目的路径 mv oldname newname 接下来我们继续介绍两个常用的命令 一个是拷贝文件&#xff0c;一个是剪切文件 &#xff0c;或者也可以用来改名字。 cp 源路径 目的路径 “cp”用来拷贝文件或者目录&#xff0c;…

Swagger3.0(Springdoc)日常使用记录

文章目录 前言一、默认地址二、注解OperationTag 三、SpringBoot基础配置四、Swagger导入apifox五、Swagger其他配置六 knife4j 参考文章 前言 本文并不是Swagger的使用教程&#xff0c;只是记录一下本人的操作&#xff0c;感兴趣的可以看下 一、默认地址 http://localhost:…

38-数组 _ 一维数组

38-1 数组的创建 数组是一组相同类型元素的集合。 数组的创建方式&#xff1a; type_t arr_name [const_n]; //type_t 是指数组的元素类型 //const_n是一个常量表达式&#xff0c;用来指定数组的大小 举例&#xff1a; int arr[10]; char ch[5]; double data[20]; 问&…

Vue基础:为什么要学Vue3,Vue3相较于Vue2有那些优势?

为什么要学Vue3&#xff1f; 1.框架层面 1.响应式底层API的变化 Proxy 数组下标的修改 对象动态添加属性 解释说明&#xff1a;1.vue2采用的是Object.definePrototype&#xff0c;它每次只能对单个对象中的单个数据进行劫持&#xff0c;所以在Vue2中data()中的数据一多就要进行…