【C++ 同余 裴蜀定理 中位数贪心 并集查找】2607. 使子数组元素和相等|2071

news2024/11/27 14:42:15

本文涉及知识点

C++贪心
数论:质数、最大公约数、菲蜀定理
C++图论

LeetCode2607. 使子数组元素和相等

给你一个下标从 0 开始的整数数组 arr 和一个整数 k 。数组 arr 是一个循环数组。换句话说,数组中的最后一个元素的下一个元素是数组中的第一个元素,数组中第一个元素的前一个元素是数组中的最后一个元素。
你可以执行下述运算任意次:
选中 arr 中任意一个元素,并使其值加上 1 或减去 1 。
执行运算使每个长度为 k 的 子数组 的元素总和都相等,返回所需要的最少运算次数。
子数组 是数组的一个连续部分。
示例 1:
输入:arr = [1,4,1,3], k = 2
输出:1
解释:在下标为 1 的元素那里执行一次运算,使其等于 3 。
执行运算后,数组变为 [1,3,1,3] 。

  • 0 处起始的子数组为 [1, 3] ,元素总和为 4
  • 1 处起始的子数组为 [3, 1] ,元素总和为 4
  • 2 处起始的子数组为 [1, 3] ,元素总和为 4
  • 3 处起始的子数组为 [3, 1] ,元素总和为 4
    示例 2:

输入:arr = [2,5,5,7], k = 3
输出:5
解释:在下标为 0 的元素那里执行三次运算,使其等于 5 。在下标为 3 的元素那里执行两次运算,使其等于 5 。
执行运算后,数组变为 [5,5,5,5] 。

  • 0 处起始的子数组为 [5, 5, 5] ,元素总和为 15
  • 1 处起始的子数组为 [5, 5, 5] ,元素总和为 15
  • 2 处起始的子数组为 [5, 5, 5] ,元素总和为 15
  • 3 处起始的子数组为 [5, 5, 5] ,元素总和为 15
    提示:
    1 <= k <= arr.length <= 105
    1 <= arr[i] <= 109

同余 中位数贪心

错误想法

nums[i…i+k-1]之和等于nums[i+1…i+k],则nums[i]等于nums[i+k] 。
i1<k <i2,i1%k等于i2%k ,i2+k >= n。nums[i2…i1-1]之和等于nums[i2+1…i1] → \rightarrow nums[i2] == nums[i1]。
故本题    ⟺    \iff 同余的下标全部相等。根据中位数贪心,同余的数全部等于中的数。

并集查找

nums[i]和nums[(i+k)%nums.size()]相等,用并集查找处理间接相等。

代码

核心代码

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:
			long long makeSubKSumEqual(vector<int>& arr, int k) {
				CUnionFind uf(arr.size());				
				for (int i = 0; i < arr.size(); i++) {
					uf.Union(i, (i + k) % arr.size());
				}
				auto m = uf.GetNodeOfRegion();
				long long ans = 0;
				for (auto& [tmp,indexs] : m) {		
					vector<int> v;
					for (const auto& i : indexs) {
						v.emplace_back(arr[i]);
					}
					const int i = v.size() / 2;
					nth_element(v.begin(), v.begin() + i, v.end());
					for (const auto& n : v) {
						ans += abs(n - v[i]);
					}
				}
				return ans;
			}
		};

单元测试

vector<int> arr;
		int k;
		TEST_METHOD(TestMethod11)
		{
			arr = { 1, 4, 1, 3 }, k = 2;
			auto res = Solution().makeSubKSumEqual(arr, k);
			AssertEx(1LL, res);
		}
		TEST_METHOD(TestMethod12)
		{
			arr = { 2,5,5,7 }, k = 3;
			auto res = Solution().makeSubKSumEqual(arr, k);
			AssertEx(5LL, res);
		}
		TEST_METHOD(TestMethod13)
		{
			arr = { 10,3,8 }, k = 2;
			auto res = Solution().makeSubKSumEqual(arr, k);
			AssertEx(7LL, res);
		}
		TEST_METHOD(TestMethod14)
		{
			arr = { 10,9,1,10,5 }, k = 3;
			auto res = Solution().makeSubKSumEqual(arr, k);
			AssertEx(14LL, res);
		}

裴蜀定理

所有长度为k的子数组相等 → \rightarrow a[i] = a[i+kx]
n = nums.size()
循环数组 → \rightarrow a[i] = a[i+ny]
两者结合:a[i] = a[i+kx+ny]
根据裴蜀定理 kx+ny一定是gcd(k,n)的倍数。且存在正数解(x1,y1)使得kx+ny=gcd(k,n) 。我们对x1,y1同时乘以z,则结果是gck(k,n)的z倍。
故:kx+ny 只能是gck(k,n)的倍数,且可以是gcd(k,n)的任何倍数。
即: a[i]= a[i + z *gcd(k,n)],    ⟺    \iff 周期是gcd(k,n)

代码

class Solution {
		public:
			long long makeSubKSumEqual(vector<int>& arr, int k) {
				const int cycle = gcd(arr.size(), k);
				vector<vector<int>> v1(k);
				for (int i = 0; i < arr.size(); i++) {
					v1[i % cycle].emplace_back(arr[i]);
				}
				long long ans = 0;
				for (auto& v : v1) {
					const int i = v.size() / 2;
					nth_element(v.begin(), v.begin() + i, v.end());
					for (const auto& n : v) {
						ans += abs(n - v[i]);
					}
				}
				return ans;
			}
		};

扩展阅读

我想对大家说的话
工作中遇到的问题,可以按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。
学习算法:按章节学习《喜缺全书算法册》,大量的题目和测试用例,打包下载。重视操作
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛
失败+反思=成功 成功+反思=成功

视频课程

先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771
如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

测试环境

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

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

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

相关文章

windows系统中,在cmd窗口演练 Redis 基本操作命令

文章目录 一、Redis 介绍1.1 Redis 的应用场景1.2 Redis 的特点 二、Windows版Redis安装三、Redis Desktop Manager安装四、Redis 常用基本操作4.1 查看操作4.2 操作string类型的命令4.2.1 设置获取Key4.2.2 MSET&#xff08;Multi&#xff09;支持批量设置key、MGET支持批量获…

擎创科技声明

近日&#xff0c;我司陆续接到求职者反映&#xff0c;有自称是擎创科技招聘人员&#xff0c;冒用“上海擎创信息技术有限公司”名义&#xff0c;用“126.com”的邮箱向求职者发布招聘信息&#xff0c;要求用户下载注册APP&#xff0c;进行在线测评。 对此&#xff0c;我司郑重…

前端算法合集-2(含面试题-美团一面)

主要考察的就是数组扁平化,由浅入深吧 ①利用tostring()和split() let arr [1, 2, 3, [4, 5, 6], [7, 8, [9, 10, 11], 12], [13, 14, 15]] let newarrarr.toString().split(,) let numarrnewarr.map((item)>{itemNumber(item)return item }) console.log(numarr) ②利用…

【SpringCloud】Gateway微服务网关(gateway快速⼊⻔ 断⾔⼯⼚ 过滤器⼯⼚ 浏览器同源策略)

Gateway微服务网关 Gateway服务网关什么是Gateway网关&#xff1f;为什么需要网关&#xff1f; Gateway快速入门创建gateway服务&#xff0c;引入依赖编写配置文件yaml和路由规则重启测试 断言工厂过滤器工厂路由过滤器的种类请求头过滤器默认过滤器全局过滤器【可写自定义逻辑…

IT监控(基础篇):好的it监控系统具备什么特点?

好的IT监控系统&#xff0c;应该是什么样的呢&#xff1f; 在当今数字化时代&#xff0c;IT系统已成为企业运营的命脉。因此&#xff0c;一个高效、可靠的IT监控平台对于确保业务连续性和提高运维效率至关重要。那么&#xff0c;一个好的IT监控平台究竟应该具备哪些特点呢&…

Adobe Acrobat DC 打印PDF文件,没有打印出注释的解决方法

adobe acrobat在打印的时候&#xff0c;打印不出来注释内容&#xff08;之前一直可以&#xff0c;突然就不行&#xff09;&#xff0c;升级版本、嵌入字体等等都试过&#xff0c;也在Google找了半天和问了GPT也么找着办法。 无奈之下&#xff0c;自己通过印前检查&#xff0c;…

ARL 灯塔 | CentOS7 — ARL 灯塔搭建流程(Docker)

关注这个工具的其它相关内容&#xff1a;自动化信息收集工具 —— ARL 灯塔使用手册 - CSDN 博客 灯塔&#xff0c;全称&#xff1a;ARL 资产侦察灯塔系统&#xff0c;有着域名资产发现和整理、IP/IP 段资产整理、端口扫描和服务识别、WEB 站点指纹识别、资产分组管理和搜索等等…

Elasticsearch是做什么的?

初识elasticsearch 官方网站&#xff1a;Elasticsearch&#xff1a;官方分布式搜索和分析引擎 | Elastic Elasticsearch是做什么的&#xff1f; Elasticsearch 是一个分布式搜索和分析引擎&#xff0c;专门用于处理大规模数据的实时搜索、分析和存储。它基于 Apache Lucene …

Spring MVC 原理与源码

Spring MVC 整体代码量有 5w 行&#xff0c;通过本专栏&#xff0c;可以快速的研读核心部分的代码&#xff0c;节省你的时间。 DispatcherServlet 的流程处理如下图&#xff1a; 但是随着前后端分离&#xff0c;后端大多提供 Restful API &#xff0c;里面的 ViewResolver 和 …

监控易监测对象及指标之:Kafka中间件JMX监控指标解读

监控易作为一款功能强大的监控软件&#xff0c;旨在为企业提供全方位的IT系统监控服务。其中&#xff0c;针对Kafka中间件的JMX监控是监控易的重要功能之一。本文将详细解读监控易中Kafka的JMX监控指标&#xff0c;帮助企业更好地理解并运用这些数据进行系统性能调优和故障排查…

onlyoffice docker启用jwt并生成jwt

一、说明 本文是docker教程&#xff0c;linux/win的安装版本也类似&#xff0c;只需要修改配置文件中的secrt就可以了【Configuring JWT for ONLYOFFICE Docs - ONLYOFFICE】 二、正文开始 docker启动时候如果不想使用jwt&#xff0c;加上参数-e JWT_ENABLEDfalse就可以了&…

软件I2C的代码

I2C的函数 GPIO的配置——scl和sda都配置为开漏输出 void MyI2C_Init(void) {RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);GPIO_InitTypeDef GPIO_InitStruture;GPIO_InitStruture.GPIO_Mode GPIO_Mode_Out_OD;GPIO_InitStruture.GPIO_PinGPIO_Pin_10 | GPIO_Pin_…

Maven 项目管理工具

目录 Maven简介 Maven快速上手 Maven详细介绍 Maven工作机制 Maven安装及配置 使用IDEA创建Maven Web工程 Maven简介 Maven是 Apache 开源组织奉献的一个开源项目&#xff0c;可以翻译为“专家”或“内行”。 Maven 的本质是一个项目管理工具&#xff0c;将项目开发和管…

Ansible自动化工具

一、Ansible概述 1.1 什么是Ansible Ansible 是一个开源的自动化工具&#xff0c;用于配置管理、应用程序部署和任务自动化。它让你可以通过编写简单的 YAML 文件&#xff08;剧本&#xff0c;Playbooks&#xff09;&#xff0c;轻松管理和配置多个服务器。Ansible 的特点是无…

爬虫逆向-js进阶(续写,搭建网站)

1.搭建简单网站1 from flask import Flask,render_template import requests import json app Flask(name)# **location**的温度是**temp**度&#xff0c;天气状况&#xff1a;**desc**app.route(/) # 绑定处理函数 def index_url():location 101010100data get_weather(lo…

Rust语言编程环境的安装

简介 Rust是一门系统编程语言,专注于安全,尤其是并发安全,支持函数式和命令式以及泛型等编程范式的多范式语言。 Rust语言的特点 系统级编程:Rust语言非常适合进行底层系统级编程,如操作系统、网络协议栈、设备驱动程序等。 内存安全:Rust使用所有权(ownership)系统来…

Scrapy | 爬取笑话网来认识继承自Spider的crawlspider爬虫类

crawlspider 1. 创建crawlspider爬虫2. 实战-爬取笑话网笑话 本篇内容旨在拓展视野和知识&#xff0c;了解crawlspider的使用即可&#xff0c;主要熟悉掌握spider类的使用 CrawlSpider 提供了一种更高级的方法来定义爬取规则&#xff0c;而无需编写大量的重复代码。它基于规则…

【功能安全】汽车功能安全个人认证证书

目录 1、证书 2、课程信息 &#x1f4d6; 推荐阅读 1、证书 汽车功能安全工程师去拿类似莱茵、SGS、南德颁发的证书&#xff0c;如下&#xff1a; 2、课程信息 一般上什么课程了&#xff0c;课程信息大概如下&#xff1a; 汽车功能安全工程师认证课 &#xff08;3天&#…

【Linux】进程的挂起状态

挂起状态的前提条件 当 内存资源严重不足 时&#xff0c;操作系统会考虑将部分进程换出到磁盘上的交换空间&#xff08;swap 分区&#xff09;。这通常发生在以下几种情况下&#xff1a; 内存不足&#xff1a; 当物理内存接近耗尽时&#xff0c;操作系统会选择将一部分暂时不需…

查缺补漏----数据结构树高总结

① 对于平衡二叉树而言&#xff0c;树高的规律&#xff1a; 高度为h的平衡二叉树的含有的最少结点数&#xff08;所有非叶节点的平衡因子均为1&#xff09;&#xff1a; n01&#xff0c;n11&#xff0c;n22 含有的最多结点数&#xff1a; (高度为h的满二叉树含有的结点数) ②…