Minimum Cost to Make Array Equal

Minimum Cost to Make Array Equal

You are given two 0-indexed arrays nums and cost consisting each of n positive integers.

You can do the following operation any number of times:

  • Increase or decrease any element of the array nums by 1.

The cost of doing one operation on the `ith` element is cost[i] .

Return the minimum total cost such that all the elements of the array nums become equal.

Example 1:

Input: nums = [1,3,5,2], cost = [2,3,1,14]
Output: 8
Explanation: We can make all the elements equal to 2 in the following way:
- Increase the 0th element one time. The cost is 2.
- Decrease the 1st element one time. The cost is 3.
- Decrease the 2nd element three times. The cost is 1 + 1 + 1 = 3.
The total cost is 2 + 3 + 3 = 8.
It can be shown that we cannot make the array equal with a smaller cost.

Example 2:

Input: nums = [2,2,2,2,2], cost = [4,2,8,1,3]
Output: 0
Explanation: All the elements are already equal, so no operations are needed.

Constraints:

  • n == nums.length == cost.length
  • 1n105
  • 1nums[i],cost[i]106

 

解题思路

  数学题,先把式子写出来,假设最终所有的数字都变成x,那么答案就是i=1n|aix|ci

  现在要求这个式子的最小值。假设ai已经从小到大排好序,且x[ak,ak+1),那么

     i=1n|aix|ci=i=1k(xai)ci+i=k+1n(aix)ci=i=1kcixi=1kaicii=k+1ncix+i=k+1naici=(i=1kcii=k+1nci)x+i=k+1naicii=1kaici

  记sci=j=1icjsi=j=1iajcj,那么上式就可以表示成(2sckscn)x+(sn2sk)

  容易发现这个式子是一个一元线性方程,要取得式子的最小值那么x一定是取定义域的端点处,即x=akx=ak+1。因此可以先预处理出来前缀和scs,然后枚举所有的ak,把相应的值带到式子中求最小值。

  AC代码如下:

复制代码
 1 class Solution {
 2 public:
 3     long long minCost(vector<int>& nums, vector<int>& cost) {
 4         int n = nums.size();
 5         vector<int> p;
 6         for (int i = 0; i < n; i++) {
 7             p.push_back(i);
 8         }
 9         sort(p.begin(), p.end(), [&](int i, int j){ // 对nums从小到大排序
10             return nums[i] < nums[j];
11         });
12         vector<long long> sc(n + 1), s(n + 1);
13         for (int i = 1; i <= n; i++) {  // 预处理前缀和
14             sc[i] = sc[i - 1] + cost[p[i - 1]];
15             s[i] = s[i - 1] + 1ll * nums[p[i - 1]] * cost[p[i - 1]];
16         }
17         long long ret = 9e18;
18         for (int i = 1; i <= n; i++) {  // 枚举所有一元线性方程的端点求最小值
19             ret = min(ret, (sc[i] - (sc[n] - sc[i])) * nums[p[i - 1]] + s[n] - s[i] - s[i]);
20         }
21         return ret;
22     }
23 };
复制代码

  再给出另外一种做法,是关于中位数的结论,这个还是很难想到的。

  首先有结论,对于问题mini=1n|aix|,当x=an+1 2,即xa的中位数时,式子能够取到最小值(a已从小到大排序)。

  而现在的问题是mini=1n|aix|cici就相当于带了权值(上面式子的ci均为1),但一样可以用上面的方法来求,只需要将|aix|ci看作是ci个系数为1|aix|累加。

  因此思路就变成了求i=1nci的中位数mid,然后取x=amid带到式子里算答案就可以了。

  AC代码如下:

复制代码
 1 class Solution {
 2 public:
 3     long long minCost(vector<int>& nums, vector<int>& cost) {
 4         int n = nums.size();
 5         vector<int> p;
 6         for (int i = 0; i < n; i++) {
 7             p.push_back(i);
 8         }
 9         sort(p.begin(), p.end(), [&](int i, int j){
10             return nums[i] < nums[j];
11         });
12         long long mid = accumulate(cost.begin(), cost.end(), 1ll) - 1 >> 1;
13         long long s = 0, x;
14         for (int i = 0; i < n; i++) {
15             s += cost[p[i]];
16             if (s > mid) {  // 此时中位数就是nums[p[i]]
17                 x = nums[p[i]];
18                 break;
19             }
20         }
21         long long ret = 0;
22         for (int i = 0; i < n; i++) {
23             ret += 1ll * abs(nums[i] - x) * cost[i];
24         }
25         return ret;
26     }
27 };
复制代码

 

参考资料

  数学 & 枚举:https://leetcode.cn/problems/minimum-cost-to-make-array-equal/solution/by-tsreaper-8hxm/

  【小羊肖恩】第 316 场力扣周赛题解:https://leetcode.cn/circle/discuss/uO4WuN/view/CUy95z/

posted @   onlyblues  阅读(72)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
Web Analytics
点击右上角即可分享
微信分享提示