在不使用数组的情况下,在几个整数中获取最多的数字

时间:2016-09-26 19:53:13

标签: frequency pseudocode

免责声明:这里有理论上的问题,而不是寻找正确的回答,只是要求一些灵感!

考虑一下:

重复调用函数并根据种子返回整数(相同的种子返回相同的整数)。您的任务是找出最常返回的整数。很容易,对吧?

但是:您不能使用数组或字段存储所述函数的返回值!

示例:

int mostFrequentNumber = 0;
int occurencesOfMostFrequentNumber = 0;
int iterations = 10000000;

for(int i = 0; i < iterations; i++)
{
    int result = getNumberFromSeed(i);
    int occurencesOfResult = magic();
    if(occurencesOfResult > occurencesOfMostFrequentNumber)
    {
        mostFrequentNumber = result;
        occurencesOfMostFrequentNumber = occurencesOfResult;
    }
}

如果getNumberFromSeed()返回 2,1,5,18,5,6 5 ,则mostFrequentNumber 5 < / em>和occurencesOfMostFrequentNumber应为 3 ,因为5次返回3次。

我知道这可以通过二维列表轻松解决,以存储结果和出现。但想象一下你不能使用任何类型的数组,列表,字典等(也许是因为运行代码的系统具有如此有限的内存,你不能一次存储足够的整数或因为你的史前编程语言没有收藏的概念。)

您如何找到mostFrequentNumberoccurencesOfMostFrequentNumbermagic()做了什么? (因为你不必坚持示例代码。欢迎任何想法!)

编辑:我应该补充说getNumber()返回的整数应该使用种子来计算,所以相同的种子返回相同的整数(即int result = getNumber(5);这总是将相同的值分配给result

2 个答案:

答案 0 :(得分:0)

做出一个假设:假设整数的分布是,例如,正常。

开始简单。有两个变量

N到目前为止读取的元素数量

M1所述元素的平均值。

将两个变量初始化为0

每次您阅读新值x更新NN + 1M1M1 + (x - M1)/N

最后M1将等于所有值的平均值。如果分布为Normal,则此值将具有较高的频率。

现在改进上述内容。添加第三个变量:

M2到目前为止所有(x - M1)^2值的所有x的平均值。

M2初始化为0。现在得到一个简短的10个元素的记忆。对于您阅读的每个新值x,如上所述更新NM1,并将M2更新为:

M2 := M2 + (x - M1)^2 * (N - 1) / N

每一步M2都是分布的方差,sqrt(M2)是标准偏差。

在您继续操作时,请记住到目前为止读取的值与M1的距离小于sqrt(M2)的频率。这需要使用一些额外的数组,但是,与您将运行的大量迭代相比,该数组将非常短。此修改将允许您更好地猜测最常见的值,而不是简单地回答上述平均值(或平均值)。

<强>更新

鉴于这是关于灵感的见解,我有足够的空间来考虑和调整我对任何特定情况提出的方法。这是一些想法

  1. 当我说假设分布正常时,您应该将其视为:假设问题没有解决方案,那么让我们看看是否有一些定性信息我可以用来决定数据的分布类型。鉴于该算法旨在找到最常见的数字,假设分布不均匀应该没问题。让我们尝试使用 Normal LogNormal 等来查看可以找到的内容(详见下文)。

  2. 如果游戏完全不允许使用任何阵列,那么很好,只记录10个数字。这将允许您计算10个最佳候选人的出现次数,这将使您对答案更有信心。在这样做时,根据您的假设的分布选择理论最可能值的候选人。

  3. 您不能使用数组,但也许您可以阅读数字序列两到三次,而不只是一次。在这种情况下,您可以阅读一次,以检查您对其分布的假设是好还是坏。例如,如果您不仅计算方差,而且计算偏度和峰度,您将有更多元素来检查您的假设。例如,如果第一个读数表明存在偏差,则可以改为使用 LogNormal 分布等。

  4. 最后,除了提供近似答案外,您还可以使用阅读期间收集的信息来估算答案周围的置信区间。

答案 1 :(得分:0)

好吧,我自己找到了一个不错的解决方案:

int mostFrequentNumber = 0;
int occurencesOfMostFrequentNumber = 0;
int iterations = 10000000;
int maxNumber = -2147483647;
int minNumber = 2147483647;

//Step 1: Find the largest and smallest number that _can_ occur
for(int i = 0; i < iterations; i++)
{
    int result = getNumberFromSeed(i);
    if(result > maxNumber)
    {
        maxNumber = result;
    }
    if(result < minNumber)
    {
        minNumber = result;
    }
}

//Step 2: for each possible number between minNumber and maxNumber, count occurences
for(int thisNumber = minNumber; thisNumber <= maxNumber; thisNumber++)
{
    int occurenceOfThisNumber = 0;
    for(int i = 0; i < iterations; i++)
    {
        int result = getNumberFromSeed(i);
        if(result == thisNumber)
        {
            occurenceOfThisNumber++;
        }
    }
    if(occurenceOfThisNumber > occurencesOfMostFrequentNumber)
    {
        occurencesOfMostFrequentNumber = occurenceOfThisNumber;
        mostFrequentNumber = thisNumber;
    }   
}

我必须承认,这可能需要很长时间,具体取决于最小和最大可能。但它可以在不使用数组的情况下工作。