C++前缀和算法的应用:使数组相等的最小开销

简介: C++前缀和算法的应用:使数组相等的最小开销

本文涉及的基础知识点

C++算法:前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频

题目

给你两个下标从 0 开始的数组 nums 和 cost ,分别包含 n 个 正 整数。

你可以执行下面操作 任意 次:

将 nums 中 任意 元素增加或者减小 1 。

对第 i 个元素执行一次操作的开销是 cost[i] 。

请你返回使 nums 中所有元素 相等 的 最少 总开销。

示例 1:

输入:nums = [1,3,5,2], cost = [2,3,1,14]

输出:8

解释:我们可以执行以下操作使所有元素变为 2 :

  • 增加第 0 个元素 1 次,开销为 2 。
  • 减小第 1 个元素 1 次,开销为 3 。
  • 减小第 2 个元素 3 次,开销为 1 + 1 + 1 = 3 。
    总开销为 2 + 3 + 3 = 8 。
    这是最小开销。
    示例 2:
    输入:nums = [2,2,2,2,2], cost = [4,2,8,1,3]
    输出:0
    解释:数组中所有元素已经全部相等,不需要执行额外的操作。
    参数范围
    n == nums.length == cost.length
    1 <= n <= 105
    1 <= nums[i], cost[i] <= 106
    测试用例确保输出不超过 253-1。

分析

原理

假定最后所有数都变成x,那么x的取值范围是[min(nums),max(nums)]。如果x1<nin(nums),那要先变成min(nums),再继续变,显然x1的开销更大。

假定x为x1,开销为ll1,如果x为x1+1,那么开销会如何变化。

如果nums[i]小于x 开销增加,比之前多增加1
如果nums[i]等于x 开销增加,之前不变,现在加1
如果nums[i]等于x+1 开销减少,之前-1,现在不变
如果nums[i]大于x+1 开销减少,比之前少1

时间复杂度

分四步,每个时间复杂度都是O(n),故总时间复杂度是O(n)。

步骤

求将各值加1,减少1的消耗,一个值可能有多个,也可能没有
求值小于j的所有数加1或减少1的消耗,也就是前缀和。
所有的数变成0的消耗
枚举x。

代码

核心代码

class Solution {
public:
long long minCost(vector& nums, vector& cost) {
m_c = nums.size();
const int iMaxValue = *std::max_element(nums.begin(), nums.end());
vector vValueConst(iMaxValue+1);//vValueConst[j] 表示将所有nums[i]等于j 加或减1 的消耗
for (int i = 0; i < m_c; i++)
{
vValueConst[nums[i]] += cost[i];
}
vector vSum = { 0 };//vValueConst[j] 表示将所有nums[i]<j 加或减1 的消耗
for (const auto& ll : vValueConst )
{
vSum.emplace_back(ll + vSum.back());
}
long long ll = 0;//记录将所有值变成x 的总消耗
for (int i = 0; i < m_c; i++)
{
ll += abs(nums[i] - 0LL) * cost[i];
}
long long llRet = LLONG_MAX;
for (int x = 0; x < iMaxValue; x++)
{
//[0,x+1) 消耗增加
ll += vSum[x + 1] - vSum[0];
//[x+1,…)
ll -= vSum.back() - vSum[x+1];
llRet = min(llRet, ll);
}
return llRet;
}
int m_c;
};

测试用例

int main()
{
Solution slu;
vector nums, cost;
long long res;
nums = { 1, 3, 5, 2 };
cost = { 2, 3, 1, 14 };
res = slu.minCost(nums,cost);
Assert(8LL ,res);
//CConsole::Out(res);

}

2023年3月旧代码

class Solution {
public:
long long minCost(vector& nums, vector& cost) {
m_c = nums.size();
Init(nums,cost);
return Cost();
}
long long Cost()
{
long long llMin = (1000LL) * 1000 * 1000 * 1000 * 1000 * 1000;
long long llLeftCost = 0, llRightCost = 0;
for (int i = 1; i < m_c; i++)
{
llRightCost += abs((long long)m_vNums[i] - m_vNums[0])*m_vCost[i];
}
llMin = min(llMin, llLeftCost+llRightCost);
for (int i = 1; i < m_c; i++)
   {
     llLeftCost += m_vSums[i]*(m_vNums[i] - m_vNums[i - 1]);
     llRightCost -= (m_vSums.back() - m_vSums[i ])*(m_vNums[i] - m_vNums[i - 1]);
     llMin = min(llMin, llLeftCost + llRightCost);
   }
   return llMin;
 }
 void Init(const vector<int>& nums,const vector<int>& cost)
 {
   std::multimap<int, int> m;
   for (int i = 0; i < m_c; i++)
   {
     m.emplace(nums[i], cost[i]);
   }
   for (const auto& it : m)
   {
     m_vNums.push_back(it.first);
     m_vCost.push_back(it.second);
   }
   m_vSums.push_back(0);
   for (const auto& n : m_vCost)
   {
     m_vSums.push_back(m_vSums.back() + n);
   }
 }
 int m_c;
 vector<int> m_vNums, m_vCost;
 vector<long long> m_vSums;

};

扩展阅读

视频课程

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


相关文章
|
3月前
|
存储 监控 JavaScript
基于布隆过滤器的 Node.js 算法在局域网电脑桌面监控设备快速校验中的应用研究
本文探讨了布隆过滤器在局域网电脑桌面监控中的应用,分析其高效空间利用率、快速查询性能及动态扩容优势,并设计了基于MAC地址的校验模型,提供Node.js实现代码,适用于设备准入控制与重复数据过滤场景。
185 0
|
1月前
|
Ubuntu API C++
C++标准库、Windows API及Ubuntu API的综合应用
总之,C++标准库、Windows API和Ubuntu API的综合应用是一项挑战性较大的任务,需要开发者具备跨平台编程的深入知识和丰富经验。通过合理的架构设计和有效的工具选择,可以在不同的操作系统平台上高效地开发和部署应用程序。
103 11
|
2月前
|
运维 监控 JavaScript
基于 Node.js 图结构的局域网设备拓扑分析算法在局域网内监控软件中的应用研究
本文探讨图结构在局域网监控系统中的应用,通过Node.js实现设备拓扑建模、路径分析与故障定位,提升网络可视化、可追溯性与运维效率,结合模拟实验验证其高效性与准确性。
228 3
|
2月前
|
机器学习/深度学习 资源调度 算法
遗传算法模型深度解析与实战应用
摘要 遗传算法(GA)作为一种受生物进化启发的优化算法,在复杂问题求解中展现出独特优势。本文系统介绍了GA的核心理论、实现细节和应用经验。算法通过模拟自然选择机制,利用选择、交叉、变异三大操作在解空间中进行全局搜索。与梯度下降等传统方法相比,GA不依赖目标函数的连续性或可微性,特别适合处理离散优化、多目标优化等复杂问题。文中详细阐述了染色体编码、适应度函数设计、遗传操作实现等关键技术,并提供了Python代码实现示例。实践表明,GA的成功应用关键在于平衡探索与开发,通过精心调参维持种群多样性同时确保收敛效率
|
2月前
|
机器学习/深度学习 边缘计算 人工智能
粒子群算法模型深度解析与实战应用
蒋星熠Jaxonic是一位深耕智能优化算法领域多年的技术探索者,专注于粒子群优化(PSO)算法的研究与应用。他深入剖析了PSO的数学模型、核心公式及实现方法,并通过大量实践验证了其在神经网络优化、工程设计等复杂问题上的卓越性能。本文全面展示了PSO的理论基础、改进策略与前沿发展方向,为读者提供了一份详尽的技术指南。
粒子群算法模型深度解析与实战应用
|
2月前
|
机器学习/深度学习 算法 安全
小场景大市场:猫狗识别算法在宠物智能设备中的应用
将猫狗识别算法应用于宠物智能设备,是AIoT领域的重要垂直场景。本文从核心技术、应用场景、挑战与趋势四个方面,全面解析这一融合算法、硬件与用户体验的系统工程。
|
1月前
|
机器学习/深度学习 算法 机器人
【水下图像增强融合算法】基于融合的水下图像与视频增强研究(Matlab代码实现)
【水下图像增强融合算法】基于融合的水下图像与视频增强研究(Matlab代码实现)
196 0
|
1月前
|
数据采集 分布式计算 并行计算
mRMR算法实现特征选择-MATLAB
mRMR算法实现特征选择-MATLAB
144 2
|
2月前
|
传感器 机器学习/深度学习 编解码
MATLAB|主动噪声和振动控制算法——对较大的次级路径变化具有鲁棒性
MATLAB|主动噪声和振动控制算法——对较大的次级路径变化具有鲁棒性
198 3
|
1月前
|
机器学习/深度学习 算法 机器人
使用哈里斯角Harris和SIFT算法来实现局部特征匹配(Matlab代码实现)
使用哈里斯角Harris和SIFT算法来实现局部特征匹配(Matlab代码实现)
137 8

热门文章

最新文章