pandigital检查的快速算法

时间:2013-03-03 18:42:07

标签: c#

我正在开发一个项目,我需要一个非常快速的算法来检查所提供的数字是否为pandigital。虽然逻辑看似合理,但我对下面描述的方法的性能并不特别满意。

我可以分别在大约520ms,600ms和1600ms内检查多达一百万个9位数字。我正在开发一个低延迟的应用程序,在生产中我将有一个大约9或95亿7到9位数字的数据集,我需要检查。

我现在有三个候选人(好吧,真的两个)使用以下逻辑:

方法1:我接受一个输入N,拆分成其组成数字的字节数组,使用Array.Sort函数对其进行排序,然后使用检查元素与计数器一致性的for循环:

 byte[] Digits = SplitDigits(N);
 int len = NumberLength(N);
 Array.Sort(Digits);
 for (int i = 0; i <= len - 1; i++)
 {
     if (i + 1 != Digits[i])
          return false;
 }

方法2:此方法基于一些可疑的逻辑,但我将输入N拆分为组成数字的字节数组,然后进行以下测试:

 if (N * (N + 1) * 0.5 == DigitSum(N) && Factorial(len) == DigitProduct(N))
      return true;

方法3:我不喜欢这个方法,所以不是真正的候选人,但我将int转换为字符串然后使用String.Contains来确定所需的字符串是否为pandigital。

第二种和第三种方法具有相当稳定的运行时间,但第一种方法反弹很多 - 有时可能高达620ms。

理想情况下,我真的希望将百万9位数字的运行时间缩短到10毫秒以下。有什么想法吗?

我在2GHz的奔腾6100笔记本电脑上运行。

PS - 是第二种方法声音的数学逻辑吗?

2 个答案:

答案 0 :(得分:1)

方法1

预先计算362880个9位数字数字的排序列表。这将只需几毫秒。然后对于每个请求,首先检查数字是否可以被9整除:它必须是pandigital。如果是,则使用二进制搜索来检查它是否在预先计算的列表中。

方法2

再次检查数字是否可以被9整除。然后使用位向量来跟踪数字的存在。也可以使用模乘法来乘以乘法。

static bool IsPandigital(int n)
{
    if (n != 9 * (int)((0x1c71c71dL * n) >> 32))
        return false;

    int flags = 0;
    while (n > 0) {
        int q = (int)((0x1999999aL * n) >> 32);
        flags |= 1 << (n - q * 10);
        n = q;
    }
    return flags == 0x3fe;
}

方法1以15ms / 1M进入。方法2在我的机器上以 5.5ms / 1M 进入。这是在i7 950上编译为x64的C#。

答案 1 :(得分:0)

只是一个想法:(在维基百科对pandigital进行定义之后)

int n = 1234567890;
int Flags = 0;
int Base = 10;
while(n != 0)
{
    Flags |= 1<<(n % Base); n /= Base;
}
bool bPanDigital = Flags == ((1 << Base) - 1);