繁体   English   中英

如何计算将数组中的所有n个数字转换为m的最小成本?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM