【动态规划】【数论】【区间合并】3041. 修改数组后最大化数组中的连续元素数目

news2025/1/14 0:49:00

作者推荐

视频算法专题

本文涉及知识点

动态规划汇总
数论 区间合并

LeetCode3041. 修改数组后最大化数组中的连续元素数目

给你一个下标从 0 开始只包含 正 整数的数组 nums 。
一开始,你可以将数组中 任意数量 元素增加 至多 1 。
修改后,你可以从最终数组中选择 一个或者更多 元素,并确保这些元素升序排序后是 连续 的。比方说,[3, 4, 5] 是连续的,但是 [3, 4, 6] 和 [1, 1, 2, 3] 不是连续的。
请你返回 最多 可以选出的元素数目。
示例 1:
输入:nums = [2,1,5,1,1]
输出:3
解释:我们将下标 0 和 3 处的元素增加 1 ,得到结果数组 nums = [3,1,5,2,1] 。
我们选择元素 [3,1,5,2,1] 并将它们排序得到 [1,2,3] ,是连续元素。
最多可以得到 3 个连续元素。
示例 2:
输入:nums = [1,4,7,10]
输出:1
解释:我们可以选择的最多元素数目是 1 。
提示:
1 <= nums.length <= 105
1 <= nums[i] <= 106

数论

先排序。
合并方式一:如果[left,r]中的数至少出现1次,则可以通过将所有数+1,从[left,r]转化成[left+1,r+1]。
合并方式二:如果[left,r]中的数至少出现1次,且至少一个数x出现两次。则可以将[left,r]转化成[left,r+1]。x → \rightarrow x+1,x+1 → \rightarrow x+2 ⋯ \cdots r → \rightarrow r+1。 如: {1,1,2,3} → \rightarrow {1,2,3,4}
如果 [l1,r1] 和[l2,r2] 是合法区间,r1+2= l2
方式一合并后,变成[l1+1,r2] ,由于缺少l1,合并后无法合并更小的区间。
方式二合并后,变成[l1,r2],可以继续合并更小的区间。
合并后的重复数字以[l2,r2]为准,[l1,r1]无论有多少个数字多不能变成r1+2,所以不会影响新区间。
我们枚举方式二的开始,如果 [l1,r1] 和[l2,r2] 能通过方式二合并,则无需枚举[l2,r2]。

代码

核心代码


template<class ELE>
void MaxSelf(ELE* seft, const ELE& other)
{
	*seft = max(*seft, other);
}

#define MacEnumMask(mask,maskMax) for (int mask = maskMax; mask; mask = (mask - 1) & maskMax) 

class Solution {
public:
	int maxSelectedElements(vector<int>& nums) {
		sort(nums.begin(), nums.end());
		vector<tuple<int, int, bool>> vLRTow;
		int left = 0;
		bool bRepeat = false;
		for (int i = 1; i < nums.size(); i++)
		{
			if (nums[i] == nums[i - 1])
			{
				bRepeat = true;
			}
			else if (nums[i] != nums[i - 1] + 1)
			{
				vLRTow.emplace_back(nums[left], nums[i - 1], bRepeat);
				left = i;
				bRepeat = false;
			}
		}
		vLRTow.emplace_back(nums[left], nums.back(), bRepeat);
		std::unordered_map<int, int> mEndToLen;
		for (const auto& [left, r, tmp] : vLRTow)
		{
			mEndToLen[r] = r - left + 1;
		}

		vector<tuple<int, int, bool>> vLRTow2;
		for (int i = 0; i  < vLRTow.size(); )
		{		
			vLRTow2.emplace_back(vLRTow[i]);
			i++;
			for ( ; i < vLRTow.size(); i ++)
			{
				if (get<2>(vLRTow2.back()) && (get<1>(vLRTow2.back()) + 2 == get<0>(vLRTow[i])))
				{
					get<2>(vLRTow2.back()) = get<2>(vLRTow[i]);
					get<1>(vLRTow2.back()) = get<1>(vLRTow[i]);
				}
				else
				{
					break;
				}
			}			
		}		
		int iRet = 0;
		for (int i = 0 ; i < vLRTow2.size();i++)
		{
			const auto& [left, r, bReapt] = vLRTow2[i];
			int pre = mEndToLen.count(left-2 )? mEndToLen[left-2] :0;
			MaxSelf(&iRet, pre + r - left + 1 + bReapt);
		}
		return iRet;
	}
};

测试用例

int main()
{
	vector<int> nums;
	
	{
		Solution sln;
		nums = { 16,1,6,14,5,10,16,3,3,7,12,18,6,11,10,10,9,16 };
		auto res = sln.maxSelectedElements(nums);
		Assert(13, res);
	}
	{
		Solution sln;
		nums = { 9, 8, 8, 5, 15, 9, 12, 5, 1, 3, 7, 18, 10 };
		auto res = sln.maxSelectedElements(nums);
		Assert(9, res);
	}
	{
		Solution sln;
		nums = { 8,13,18,10,16,19,11,17,15,18,9,12,15,8,9,14,7 };
		auto res = sln.maxSelectedElements(nums);
		Assert(14, res);
	}
	{
		Solution sln;
		nums = { 12, 11, 8, 7, 2, 10, 18, 12 };
		auto res = sln.maxSelectedElements(nums);
		Assert(6, res);
	}
	{
		Solution sln;
		nums = { 8,10,6,12,9,12,2,3,13,19,11,18,10,16 };
		auto res = sln.maxSelectedElements(nums);
		Assert(8, res);
	}
	
	{
		Solution sln;
		nums = { 2,1,4,1,1 };
		auto res = sln.maxSelectedElements(nums);
		Assert(4, res);
	}
	{
		Solution sln;
		nums = { 2,1,5,1,1 };
		auto res = sln.maxSelectedElements(nums);
		Assert(3, res);
	}	
}

优化代码:简洁


template<class ELE>
void MaxSelf(ELE* seft, const ELE& other)
{
	*seft = max(*seft, other);
}

#define MacEnumMask(mask,maskMax) for (int mask = maskMax; mask; mask = (mask - 1) & maskMax) 

class Solution {
public:
	int maxSelectedElements(vector<int>& nums) {
		sort(nums.begin(), nums.end());
		vector<tuple<int, int, bool>> vLRTow;
		int left = 0;
		bool bRepeat = false;
		for (int i = 1; i < nums.size(); i++)
		{
			if (nums[i] == nums[i - 1])
			{
				bRepeat = true;
			}
			else if (nums[i] != nums[i - 1] + 1)
			{
				vLRTow.emplace_back(nums[left], nums[i - 1], bRepeat);
				left = i;
				bRepeat = false;
			}
		}
		vLRTow.emplace_back(nums[left], nums.back(), bRepeat);
		int iRet = 0;
		for (int i = 0; i < vLRTow.size(); )
		{	
			int j = i + 1;
			int right = get<1>(vLRTow[i]) + get<2>(vLRTow[i]);
			for (; j < vLRTow.size(); j++)
			{
				if (get<2>(vLRTow[j-1]) && (get<1>(vLRTow[j - 1]) + 2 == get<0>(vLRTow[j])))
				{
					right = get<1>(vLRTow[j]) + get<2>(vLRTow[j]);
				}
				else
				{
					break;
				}
			}			
			int pre = ((i > 0) && (get<1>(vLRTow[i - 1]) + 2 == get<0>(vLRTow[i]))) ? (get<1>(vLRTow[i - 1]) - get<0>(vLRTow[i - 1]) + 1) : 0;
			MaxSelf(&iRet, right - get<0>(vLRTow[i])+1 + pre );
			i = j;
		}
		return iRet;
	}
};

动态规划

动态规划的状态

dp[x]表示以x结尾的最长连续数量。

动态规划的初始值

无,或者或全部为0。

动态规划的状态方程

{ d p [ x + 1 ] = m a x ( d p [ x + 1 ] , d p [ x ] + 1 ) x 加一 d p [ x ] = m a x ( d p [ x ] , d p [ x − 1 ] + 1 ) x 不变 \begin{cases} dp[x+1] = max(dp[x+1],dp[x]+1) & x加一 \\ dp[x] = max(dp[x],dp[x-1]+1) & x不变\\ \end{cases} {dp[x+1]=max(dp[x+1],dp[x]+1)dp[x]=max(dp[x],dp[x1]+1)x加一x不变

动态规划的填表顺序

x从小到大。先处理x+1,再处理x。否则{1}的结果是dp[1]=1,dp[2]=2。

代码

template<class ELE>
void MaxSelf(ELE* seft, const ELE& other)
{
	*seft = max(*seft, other);
}

class Solution {
public:
	int maxSelectedElements(vector<int>& nums) {
		sort(nums.begin(), nums.end());
		unordered_map<int, int> dp;
		for (const auto& n : nums)
		{
			MaxSelf(&dp[n + 1], dp[n] + 1);
			MaxSelf(&dp[n ], dp[n - 1] + 1);
		}
		int iRet = 0;
		for (const auto& [tmp, len] : dp)
		{
			MaxSelf(&iRet, len);
		}
		return iRet;
	}
};

扩展阅读

视频课程

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

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

相关文章

java网络编程 02 socket

01.socket定义 02.TCP编程 import java.io.IOException; import java.io.OutputStream; import java.net.InetAddress; import java.net.Socket;public class clientSocket {public static void main(String[] args) throws IOException {//创建客户端socket&#xff0c;…

Get了!原来朋友圈定时发布如此简单!

你是不是也有这样的烦恼&#xff1f;微信号太多&#xff0c;有时候会顾不上发朋友圈&#xff1f; 别担心&#xff01;微信管理系统来帮你解决这个问题&#xff0c;实现朋友圈定时发布&#xff01;让我们一起来看看如何利用微信管理系统的强大功能来提升我们的社交媒体效率吧。…

请说明Vue中的解耦能力

Vue中的解耦能力是指在Vue框架中&#xff0c;我们能够有效地将代码分离成独立的组件或模块&#xff0c;使得这些组件之间的依赖关系减少&#xff0c;实现高内聚、低耦合的设计目标。利用Vue中的组件化开发&#xff0c;可以让不同的模块之间更容易地通信和协作&#xff0c;提高代…

echarts中toolbox 中文乱码问题

问题描述 本地引用的echarts源文件&#xff0c;页面其他部分编码显示正常&#xff0c;唯独toolbox鼠标悬停在上面时提示信息显示乱码。 如图所示&#xff1a; 尝试过的方法 使用sublime text 3&#xff0c;notepad&#xff0c;记事本更改文件编码为utf-8引入时&#xff0c;在sc…

短剧小程序:掌中剧院,随时演绎精彩

在快节奏的现代生活中&#xff0c;人们越来越追求高效与便捷。为了满足广大用户对短剧内容的热爱和追求&#xff0c;我们推出了全新的短剧小程序&#xff0c;让精彩剧情触手可及&#xff0c;随时随地为您带来欢乐与感动。 一、轻松点播&#xff0c;随享短剧魅力 通过短剧小程…

软件系统开发安全指南-word

应用系统设计安全主要涵盖以下几点&#xff1a; 1、应用系统架构安全设计 2、应用系统软件功能安全设计 3、应用系统存储安全设计 4、应用系统通讯安全设计 5、应用系统数据库安全设计 应用系统测试安全包含&#xff1a; 1、测试前置要求 2、测试方法及测试内容 3、测试环境及人…

10大AI工具

ChatGPT ChatGPT是由OpenAI开发的人工智能聊天机器人程序&#xff0c;全称为Chat Generative Pre-trained Transformer。它基于GPT-3.5架构&#xff0c;能够生成回答并根据聊天上下文进行互动。ChatGPT具备强大的对话能力&#xff0c;能在同一会话中回答上下文相关的问题&…

安卓简单登录

注意 有的朋友不知道登录咋写&#xff0c;这里我就简单给出相应代码&#xff0c;用的本地存储&#xff0c;没用网络请求&#xff0c;有需要可以替换成想要的&#xff0c;废话不多上代码 登录 import androidx.appcompat.app.AppCompatActivity;import android.content.Context…

JavaWeb----MySQL

一&#xff1a;JavaWeb相关介绍 Web&#xff1a;全球广域网&#xff0c;也称为万维网&#xff08;www&#xff09;&#xff0c;能够通过浏览器访问的网站 JavaWeb&#xff1a;是用Java技术来解决相关Web互联网领域的技术栈 JavaWeb流程 1.网页&#xff1a;展现数据 2.数据…

postman只读模式的解决办法

我大概是多次复制参数&#xff08;或是别的操作&#xff09;&#xff0c;进入了postman的只读模式。这时无法修改页面的传参&#xff0c;而且右上角的save按钮是灰色&#xff08;不可选&#xff09; 下面分享我的2种解决办法 第一种方法 在任务栏右键选中接口&#xff0c;选…

RUST 每日一省:发布到crates.io

github是开源代码分享的地方&#xff0c;rust的开源项目除了github&#xff0c;我们还可以将其发布到 crates.io 上&#xff0c;然后其它用户就可以使用cargo进行安装使用了。其实步骤很简单&#xff0c;只有三条命令了&#xff0c;我们一次来看一下。 1、cargo package 首先&a…

使用Navicat连接阿里云服务器上的MySQL数据库

打开navicat&#xff0c;连接如下&#xff1a; 服务器的默认密码是 root 连接时出现 使用 ls 查找 /etc/my.cnf ls /etc/my.cnf 用vi打开my.cnf&#xff1a; vi /etc/my.cnf看看是否有绑定本地回环地址的配置&#xff0c;如果有&#xff0c;注释掉下面这段文字&#xff1a;…

GitHub Desktop的常用操作【图形化】

文章目录 【1】仓库的创建和删除【2】文件操作【3】分支原理与分支操作1.分支创建2.分支合并 【4】标签 【1】仓库的创建和删除 在本地创建一个新的仓库&#xff1a; 然后输入仓库的名称&#xff0c;描述&#xff0c;并选择路径&#xff1a; 点击完后就发现我们的仓库创建好…

Anaconda的使用及spyder相关设置

Anaconda Anaconda是一个Python发行版&#xff0c;主要用于数据科学和机器学习领域。Anaconda集成了许多常用的数据科学工具和库&#xff0c;如NumPy、Pandas、Scikit-learn等&#xff0c;同时还包含了一个强大的包管理器conda和一个集成开发环境Spyder。Anaconda的目标是提供一…

鼠标光标选取文本、获取文本索引

1.效果图 这是在做一个字段分割的需求 2.思路 步骤一&#xff1a;通过document添加mouseup事件&#xff1b; 步骤二&#xff1a;通过window的getSelection()函数获取文本值&#xff1b; 步骤三&#xff1a;通过mouseup事件的event 类名来限制可截取元素的范围&#xff1b;…

论文解读:Meta-Baseline: Exploring Simple Meta-Learning for Few-Shot Learning

文章汇总 总体问题 通过对整体分类的训练(文章结构图中ClassifierBaseline)&#xff0c;即在整个标签集上进行分类&#xff0c;它可以得到与许多元学习算法相当甚至更好的嵌入。这两种工作之间的界限尚未得到充分的探索&#xff0c;元学习在少样本学习中的有效性仍然不清楚。…

【CSP】201403-3-命令行选项

CSP-201403-3-命令行选项 关键点&#xff1a;将整行字符串按空格分割 在解析命令行时&#xff0c;一个常见的需求是将整个命令行字符串分割成多个部分&#xff0c;通常以空格为分隔符。这些部分包括命令行工具的名称、选项&#xff08;可能带有前缀-或--&#xff09;和这些选项…

【Simulink系列】——控制系统仿真基础

声明&#xff1a;本系列博客参考有关专业书籍&#xff0c;截图均为自己实操&#xff0c;仅供交流学习&#xff01; 一、控制系统基本概念 这里就不再介绍类似于开环系统、闭环系统等基本概念了&#xff01; 1、数学模型 控制系统的数学模型是指动态数学模型&#xff0c;大致…

CGAL 5.6.1 - Algebraic Foundations

1. 引言 CGAL 的目标是精确计算非线性对象&#xff0c;特别是定义在代数曲线和曲面上的对象。因此&#xff0c;表示多项式、代数扩展和有限域的类型在相关的实现中扮演着更加重要的角色。为了跟上这些变化&#xff0c;我们引入了这个软件包。由于引入的框架必须特别支持多项式…

基于云效构建部署Springboot项目到ACK

介绍 为了提高项目迭代的速度加速交付产品给客户&#xff0c;我们通常会选择CICD工具来减少人力投入产生的成本&#xff0c;开源的工具比如有成熟的Jenkins&#xff0c;但是本文讲的是阿里云提高的解决方案云效平台&#xff0c;通过配置流水线的形式实现项目的快速部署到服务器…