【贪心】【分类讨论】2499. 让数组不相等的最小总代价

2024-03-26 19:04

本文主要是介绍【贪心】【分类讨论】2499. 让数组不相等的最小总代价,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

作者推荐

视频算法专题

本文涉及知识点

贪心 分类讨论

LeetCode2499. 让数组不相等的最小总代价

给你两个下标从 0 开始的整数数组 nums1 和 nums2 ,两者长度都为 n 。
每次操作中,你可以选择交换 nums1 中任意两个下标处的值。操作的 开销 为两个下标的 和 。
你的目标是对于所有的 0 <= i <= n - 1 ,都满足 nums1[i] != nums2[i] ,你可以进行 任意次 操作,请你返回达到这个目标的 最小 总代价。
请你返回让 nums1 和 nums2 满足上述条件的 最小总代价 ,如果无法达成目标,返回 -1 。
示例 1:
输入:nums1 = [1,2,3,4,5], nums2 = [1,2,3,4,5]
输出:10
解释:
实现目标的其中一种方法为:

  • 交换下标为 0 和 3 的两个值,代价为 0 + 3 = 3 。现在 nums1 = [4,2,3,1,5] 。
  • 交换下标为 1 和 2 的两个值,代价为 1 + 2 = 3 。现在 nums1 = [4,3,2,1,5] 。
  • 交换下标为 0 和 4 的两个值,代价为 0 + 4 = 4 。现在 nums1 = [5,3,2,1,4] 。
    最后,对于每个下标 i ,都有 nums1[i] != nums2[i] 。总代价为 10 。
    还有别的交换值的方法,但是无法得到代价和小于 10 的方案。
    示例 2:
    输入:nums1 = [2,2,2,1,3], nums2 = [1,2,2,3,3]
    输出:10
    解释:
    实现目标的一种方法为:
  • 交换下标为 2 和 3 的两个值,代价为 2 + 3 = 5 。现在 nums1 = [2,2,1,2,3] 。
  • 交换下标为 1 和 4 的两个值,代价为 1 + 4 = 5 。现在 nums1 = [2,3,1,2,2] 。
    总代价为 10 ,是所有方案中的最小代价。
    示例 3:
    输入:nums1 = [1,2,2], nums2 = [1,2,2]
    输出:-1
    解释:
    不管怎么操作,都无法满足题目要求。
    所以返回 -1 。
    提示:
    n == nums1.length == nums2.length
    1 <= n <= 105
    1 <= nums1[i], nums2[i] <= n

分类讨论

能否不相等

cnt[x]记录x在nums1和nums2中出现的总次数。cnt[x]取最大值对应的x是x1(众数)。
如果cnt[x1] > n,则一定无法不相等。nums1[i]和nums2[i]只能有一个是x,而i的取值范围是[0,n)共n种可能,顶多存放n个x。
如果cnt[x1]==n ,nums1[i]或nums2[i]中的一个等于x,另外一个不为x。故:一定能不相等。
下面来证明:cnt[x1] < n,一定能不相等。证明一
x1是众数,说明其它数<=cnt[x1] 2个x1 < 2*n,所以至少3个数。任选另外两个数各删除一个。众数不变(x1没减少,其它数减少少或不变),n–,经过优先次数n一定会等于x1。

何种顺序交换

cnt[x] 记录nums1[i]==nums2[i]==x 的数量。
令x = x1时cnt[x]取最大值。令sum = ∑ x ≠ x 1 ( c n t [ x ] ) \sum_{x\neq x1}(cnt[x]) x=x1(cnt[x])
一,cnt[x1] <= sum
如果总数量是偶数:按证明一的方法两两交换。
如果总是是奇数:说明至少3个数,总有一个数不等于nums1[0]和nums2[0],用这个数和下标0换。
二,cnt[x1] <= sum
sum个x按上述方式处理。n1 = cnt[x1]- sum个x 和符合以下条件的最小下标换。
1,没交换过,交换过的nums1[i]或nums2[i]至少一个是x1。
2,nums1[i]和nums2[i]不等于x。

代码

核心代码

class Solution {
public:long long minimumTotalCost(vector<int>& nums1, vector<int>& nums2) {{unordered_map<int, int> mNumCount;for (const auto& n : nums1){mNumCount[n]++;}for (const auto& n : nums2){mNumCount[n]++;}for (const auto& [tmp, cnt] : mNumCount){if (cnt > nums1.size()){return -1;}}}unordered_map<int, int> mNumCount;long long ans = 0;for (int i = 0; i < nums1.size(); i++){if (nums1[i] == nums2[i]){mNumCount[nums1[i]]++;ans += i;}}int x1 = -1, ctn1 = 0,total=0;for (const auto& [num, cnt] : mNumCount){if (cnt > ctn1){x1 = num;ctn1 = cnt;}total += cnt;}int iNeedChange = ctn1 - (total - ctn1);if (iNeedChange <= 0){return ans;}for (int j = 0; j < nums1.size(); j++){if ((nums1[j] == nums2[j]) || (nums1[j] == x1) || (nums2[j] == x1)){continue;}ans += j;if (--iNeedChange <= 0){return ans;}}return -1;}int m_c;
};

优化

前面的判断可以省略.

class Solution {
public:long long minimumTotalCost(vector<int>& nums1, vector<int>& nums2) {		unordered_map<int, int> mNumCount;long long ans = 0;for (int i = 0; i < nums1.size(); i++){if (nums1[i] == nums2[i]){mNumCount[nums1[i]]++;ans += i;}}int x1 = -1, ctn1 = 0,total=0;for (const auto& [num, cnt] : mNumCount){if (cnt > ctn1){x1 = num;ctn1 = cnt;}total += cnt;}int iNeedChange = ctn1 - (total - ctn1);if (iNeedChange <= 0){return ans;}for (int j = 0; j < nums1.size(); j++){if ((nums1[j] == nums2[j]) || (nums1[j] == x1) || (nums2[j] == x1)){continue;}ans += j;if (--iNeedChange <= 0){return ans;}}return -1;}int m_c;
};

测试用例

template<class T,class T2>
void Assert(const T& t1, const T2& t2)
{
assert(t1 == t2);
}

template
void Assert(const vector& v1, const vector& 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 nums1, nums2;
{
Solution sln;
nums1 = { 1, 2, 3, 4, 5 }, nums2 = { 1, 2, 3, 4, 5 };
auto res = sln.minimumTotalCost(nums1, nums2);
Assert(10, res);
}
{
Solution sln;
nums1 = { 2,2,2,1,3 }, nums2 = { 1,2,2,3,3 };
auto res = sln.minimumTotalCost(nums1, nums2);
Assert(10, res);
}
{
Solution sln;
nums1 = { 1,2,2 }, nums2 = { 2,2,1 };
auto res = sln.minimumTotalCost(nums1, nums2);
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++**实现。

这篇关于【贪心】【分类讨论】2499. 让数组不相等的最小总代价的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/849538

相关文章

MySQL JSON 查询中的对象与数组技巧及查询示例

《MySQLJSON查询中的对象与数组技巧及查询示例》MySQL中JSON对象和JSON数组查询的详细介绍及带有WHERE条件的查询示例,本文给大家介绍的非常详细,mysqljson查询示例相关知... 目录jsON 对象查询1. JSON_CONTAINS2. JSON_EXTRACT3. JSON_TA

JAVA数组中五种常见排序方法整理汇总

《JAVA数组中五种常见排序方法整理汇总》本文给大家分享五种常用的Java数组排序方法整理,每种方法结合示例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录前言:法一:Arrays.sort()法二:冒泡排序法三:选择排序法四:反转排序法五:直接插入排序前言:几种常用的Java数组排序

Pandas使用AdaBoost进行分类的实现

《Pandas使用AdaBoost进行分类的实现》Pandas和AdaBoost分类算法,可以高效地进行数据预处理和分类任务,本文主要介绍了Pandas使用AdaBoost进行分类的实现,具有一定的参... 目录什么是 AdaBoost?使用 AdaBoost 的步骤安装必要的库步骤一:数据准备步骤二:模型

Java数组初始化的五种方式

《Java数组初始化的五种方式》数组是Java中最基础且常用的数据结构之一,其初始化方式多样且各具特点,本文详细讲解Java数组初始化的五种方式,分析其适用场景、优劣势对比及注意事项,帮助避免常见陷阱... 目录1. 静态初始化:简洁但固定代码示例核心特点适用场景注意事项2. 动态初始化:灵活但需手动管理代

C++中初始化二维数组的几种常见方法

《C++中初始化二维数组的几种常见方法》本文详细介绍了在C++中初始化二维数组的不同方式,包括静态初始化、循环、全部为零、部分初始化、std::array和std::vector,以及std::vec... 目录1. 静态初始化2. 使用循环初始化3. 全部初始化为零4. 部分初始化5. 使用 std::a

shell编程之函数与数组的使用详解

《shell编程之函数与数组的使用详解》:本文主要介绍shell编程之函数与数组的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录shell函数函数的用法俩个数求和系统资源监控并报警函数函数变量的作用范围函数的参数递归函数shell数组获取数组的长度读取某下的

C++原地删除有序数组重复项的N种方法

《C++原地删除有序数组重复项的N种方法》给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度,不要使用额外的数组空间,你必须在原地修改输入数组并在使用O(... 目录一、问题二、问题分析三、算法实现四、问题变体:最多保留两次五、分析和代码实现5.1、问题分析5.

MySQL中闪回功能的方案讨论及实现

《MySQL中闪回功能的方案讨论及实现》Oracle有一个闪回(flashback)功能,能够用户恢复误操作的数据,这篇文章主要来和大家讨论一下MySQL中支持闪回功能的方案,有需要的可以了解下... 目录1、 闪回的目标2、 无米无炊一3、 无米无炊二4、 演示5、小结oracle有一个闪回(flashb

Java中数组转换为列表的两种实现方式(超简单)

《Java中数组转换为列表的两种实现方式(超简单)》本文介绍了在Java中将数组转换为列表的两种常见方法使用Arrays.asList和Java8的StreamAPI,Arrays.asList方法简... 目录1. 使用Java Collections框架(Arrays.asList)1.1 示例代码1.

C++一个数组赋值给另一个数组方式

《C++一个数组赋值给另一个数组方式》文章介绍了三种在C++中将一个数组赋值给另一个数组的方法:使用循环逐个元素赋值、使用标准库函数std::copy或std::memcpy以及使用标准库容器,每种方... 目录C++一个数组赋值给另一个数组循环遍历赋值使用标准库中的函数 std::copy 或 std::