[英]How to calculate the minimum cost to convert all n numbers in an array to m?
我得到了以下任务:
给定N个A(i)形式的整数,其中1≤i≤N,使N个数字中的每个数字A(i)等于M。要将数字A(i)转换为M,将花费| M−艾| 单位。 找出将所有N个数字都转换为M的最低成本,因此您应该选择最佳的M以获得最低成本。
鉴于:
1 <= N <= 10^5 1 <= A(i) <= 10^9
我的方法是计算所有数字的总和,发现avg = sum / n
,然后减去每个号码avg
得到的最低成本。
但这在许多测试案例中都失败了。 如何找到最佳解决方案?
您应该取数字的中位数(或者如果列表的长度为偶数,则取两个最接近中间的数字),而不是平均值。
均值无法最小化的示例是:[1、2、3、4、100]。 平均值为110/5 = 22,总成本为21 + 20 + 19 + 18 + 78 =156。选择中位数(3)得出总成本:2 + 1 + 0 + 1 + 97 = 101。
中位数位于列表中两个项目之间的示例是[1、2、3、4、5、100]。 这里的中位数是3.5,可以使用M = 3或M = 4。 对于M = 3,总成本为2 + 1 + 0 + 1 + 2 + 97 =103。对于M = 4,总成本为3 + 2 + 1 + 0 + 1 + 96 = 103。
可以在Mathematics SE上找到正确性的正式证明,尽管您可能会注意到以下事实:如果您在一个方向上(但不超过一个数据点)微调M量,则可以说服自己相信结果-例如假设这是朝着积极的方向发展,总成本将增加增量乘以M左侧的点数减去增量乘以M右侧的点数。因此,当M的左侧和左侧的点数均为右边的数字相等,否则您可以以一种或另一种方式少量移动它以降低总成本。
@PaulHankin已经提供了一个完美的答案。 无论如何,在考虑问题时,我没有想到中位数是解决方案。 但是,即使您不了解中位数,也可以提出编程解决方案。
在他的最后答案的最后一段中,我与@PaulHankin进行了类似的评论。 这使我意识到,为了找到m
,我必须迭代地消除异常值。 因此,我编写了一个程序,该程序首先对输入数组(向量) A
进行排序,然后分析最小值和最大值。
想法是将最小值移至第二最小值,将最大值移至第二最大值。 始终移动最小值或最大值,这取决于最小值是否小于最大值。 如果所有数组项最终都具有相同的值,那么您找到了m
:
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int getMinCount(vector<int>& A);
int getMaxCount(vector<int>& A);
int main()
{
// Example as given by @PaulHankin
vector<int> A;
A.push_back(1);
A.push_back(2);
A.push_back(3);
A.push_back(4);
A.push_back(100);
sort(A.begin(), A.end());
int minCount = getMinCount(A);
int maxCount = getMaxCount(A);
while (minCount != A.size() && maxCount != A.size())
{
if(minCount <= maxCount)
{
for(int i = 0; i < minCount; i++)
A[i] = A[minCount];
// Recalculate the count of the minium value, because we changed the minimum.
minCount = getMinCount(A);
}
else
{
for(int i = 0; i < maxCount; i++)
A[A.size() - 1 - i] = A[A.size() - 1 - maxCount];
// Recalculate the count of the maximum value, because we changed the maximum.
maxCount = getMaxCount(A);
}
}
// Print out the one and only remaining value, which is m.
cout << A[0] << endl;
return 0;
}
int getMinCount(vector<int>& A)
{
// Count how often the minimum value exists.
int minCount = 1;
int pos = 1;
while (pos < A.size() && A[pos++] == A[0])
minCount++;
return minCount;
}
int getMaxCount(vector<int>& A)
{
// Count how often the maximum value exists.
int maxCount = 1;
int pos = A.size() - 2;
while (pos >= 0 && A[pos--] == A[A.size() - 1])
maxCount++;
return maxCount;
}
如果您考虑一下该算法,那么您将得出结论,它实际上是计算数组A
值的中位数。 作为示例输入,我采用了@PaulHankin给出的第一个示例。 如预期的那样,该代码为其提供了正确的结果(3)。
我希望我的方法可以帮助您了解如何解决此类问题,即使您不知道正确的解决方案。 例如,在面试中,这特别有用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.