【贪心】【分类讨论】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

相关文章

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::

C++初始化数组的几种常见方法(简单易懂)

《C++初始化数组的几种常见方法(简单易懂)》本文介绍了C++中数组的初始化方法,包括一维数组和二维数组的初始化,以及用new动态初始化数组,在C++11及以上版本中,还提供了使用std::array... 目录1、初始化一维数组1.1、使用列表初始化(推荐方式)1.2、初始化部分列表1.3、使用std::

C++ Primer 多维数组的使用

《C++Primer多维数组的使用》本文主要介绍了多维数组在C++语言中的定义、初始化、下标引用以及使用范围for语句处理多维数组的方法,具有一定的参考价值,感兴趣的可以了解一下... 目录多维数组多维数组的初始化多维数组的下标引用使用范围for语句处理多维数组指针和多维数组多维数组严格来说,C++语言没

C#使用DeepSeek API实现自然语言处理,文本分类和情感分析

《C#使用DeepSeekAPI实现自然语言处理,文本分类和情感分析》在C#中使用DeepSeekAPI可以实现多种功能,例如自然语言处理、文本分类、情感分析等,本文主要为大家介绍了具体实现步骤,... 目录准备工作文本生成文本分类问答系统代码生成翻译功能文本摘要文本校对图像描述生成总结在C#中使用Deep

Java 字符数组转字符串的常用方法

《Java字符数组转字符串的常用方法》文章总结了在Java中将字符数组转换为字符串的几种常用方法,包括使用String构造函数、String.valueOf()方法、StringBuilder以及A... 目录1. 使用String构造函数1.1 基本转换方法1.2 注意事项2. 使用String.valu

JAVA中整型数组、字符串数组、整型数和字符串 的创建与转换的方法

《JAVA中整型数组、字符串数组、整型数和字符串的创建与转换的方法》本文介绍了Java中字符串、字符数组和整型数组的创建方法,以及它们之间的转换方法,还详细讲解了字符串中的一些常用方法,如index... 目录一、字符串、字符数组和整型数组的创建1、字符串的创建方法1.1 通过引用字符数组来创建字符串1.2

vue如何监听对象或者数组某个属性的变化详解

《vue如何监听对象或者数组某个属性的变化详解》这篇文章主要给大家介绍了关于vue如何监听对象或者数组某个属性的变化,在Vue.js中可以通过watch监听属性变化并动态修改其他属性的值,watch通... 目录前言用watch监听深度监听使用计算属性watch和计算属性的区别在vue 3中使用watchE