持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第29天,点击查看活动详情
力扣——2448. 使数组相等的最小开销
2448. 使数组相等的最小开销 - 力扣(LeetCode)
给你两个下标从 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 。
这是最小开销。
提示:
n == nums.length == cost.length1 <= n <= 1051 <= nums[i], cost[i] <= 106
问题解析
- 设置前缀数组f,f[i]表示:把0~i-1的元素都变成i元素的总开销为f[i]。
- 设置后缀数组f2,f2[i]表示:把i+1~n-1的元素都变成i元素的总开销为f2[i]。
- 为了方便运算,我们将nums[i]和cost[i]绑定后升序排序。
- 可以知道f[0]=0,f2[n-1]=0。剩下的该如何递推呢?
- 我们用前缀树组f来想,当我们遍历到第i个位置时,f[i-1]是把前面所有元素都变成了nums[i-1]的花费,那么我只用把这些元素都变成nums[i]即可,这一部分的花费就为:(nums[i]-nums[i-1])*(前面所有元素的cost之和)。
- 可知f的递推公式为:f[i]=f[i-1]+(nums[i]-nums[i-1])*(前面所有元素的cost之和)。
- 同理可得f2的递推公式:f[i]=f[i+1]+(nums[i+1]-nums[i])*(后面所有元素的cost之和)。
- 然后我们枚举i,维护f[i]+f2[i]的最小值即可。
AC代码
class Solution {
public:
typedef long long ll;
typedef pair<ll,ll>PII;
ll f[100050],f2[100050];
long long minCost(vector<int>& nums, vector<int>& cost) {
ll n=nums.size();
vector<PII>v(n);
for(int i=0;i<n;i++)
{
v[i].first=nums[i];
v[i].second=cost[i];
}
sort(v.begin(),v.end());
ll ans=v[0].second;
for(int i=1;i<n;i++)
{
f[i]=f[i-1]+ans*(v[i].first-v[i-1].first);
ans+=v[i].second;
}
ans=v[n-1].second;
for(int i=n-2;i>=0;i--)
{
f2[i]=f2[i+1]+ans*((v[i+1].first-v[i].first));
ans+=v[i].second;
}
ll mn=1e18;
for(int i=0;i<n;i++)
{
mn=min(mn,f[i]+f2[i]);
}
return mn;
}
};