检查num1的数字是否为num2中的数字而不检查每个数字的方法?

时间:2009-02-19 21:06:34

标签: math puzzle

让我们说我已经猜到了一个乐透号码:

  

1689

并且彩票的工作方式是,只要数字与实际中奖彩票号码中的数字1:1匹配,数字的顺序无关紧要。

因此,1689号码将是一个中奖彩票号码:

  

1896,1698,9816等。

只要您的猜测中的每个数字都出现在目标数字中,那么您就赢了彩票。

我能用这种数学方法吗?

我用O(N ^ 2)循环解决了这个问题,检查每个数字与中奖彩票号码的每个数字(用模数分隔)。哪个好,它有效,但我想知道我能做的任何简洁的数学技巧。

例如,起初......我认为我可能会很棘手,只需要拿出两个数字中每个数字的总和和乘积,如果它们匹配,那么你就赢了。

^你觉得那会起作用吗?

然而,当我发现彩票猜测时,我很快就反驳了这一点:222,124有不同的数字,但产品和数量相同。

任何人都知道我可以使用的任何数学技巧来快速确定num1中的数字是否与num2中的数字相匹配而不管顺序如何?

14 个答案:

答案 0 :(得分:16)

如何浏览每个数字,并计算每个数字的出现次数(分成两个不同的10个元素数组)?完成总计后,比较每个数字的计数。由于你只查看每个数字一次,那就是O(N)。

代码看起来像:

for(int i=0; i<digit_count; i++)
{
   guessCounts[guessDigits[i] - '0']++;
   actualCounts[actualDigits[i] - '0']++;
}

bool winner = true;
for(int i=0; i<10 && winner; i++)
{
   winner &= guessCounts[i] == actualCounts[i];
}

上面的代码假设guessDigits和actualDigits都是char字符串;如果他们持有实际数字,那么您可以跳过- '0'业务。

可能有一些优化可以减少占用空间或更快地终止,但这是O(N)方法的一个非常直接的例子。

顺便说一下,正如我在评论中提到的那样,乘法/和比率肯定不会因为零而起作用。考虑0123和0222.产品为0,两种情况下的总和为6。

答案 1 :(得分:14)

拆分为数组,排序数组,连接成字符串,比较字符串。

(不是数学技巧,我知道)

答案 2 :(得分:3)

您可以将数字放入数组中,对数组进行排序,然后逐个元素地比较数组。这将为您提供O(NlogN)复杂度,该复杂度优于O(N ^ 2)。

答案 3 :(得分:2)

如果N变大,那么排序数字就是答案。

因为数字是0..9,你可以计算数组[0..9]中彩票答案每个数字的出现次数。

要进行比较,您可以在猜测中遇到的每个数字减去1。当您遇到计数已经为0的数字时,您知道猜测是不同的。当你通过所有数字时,猜测是相同的(只要猜测的数字与彩票答案一样多)。

答案 4 :(得分:2)

对于每个数字d乘以第(d + 1)个素数。

这比排序或铲斗方法更具数学性但效率更低。实际上它是伪装的斗式方法。

答案 5 :(得分:0)

我会对两个数字进行排序并进行比较。

答案 6 :(得分:0)

在存储号码前对数字进行排序。在那之后,你的数字将是平等的。

答案 7 :(得分:0)

如果您只处理4位数,我认为您不必考虑使用哪种算法。它们的表现大致相同。

222和124也没有相同的总和

答案 8 :(得分:0)

你必须考虑当n很小时,效率的顺序是无关紧要的,并且常数开始变得更重要。你的数字实际上有多大?你能得到10位数吗? 20? 100?如果你的数字只有几位数,那么n ^ 2确实不是那么糟糕。如果你有数千个数字的字符串,那么你可能实际上需要做一些更聪明的事情,如排序或分组。 (即计算0,计算1,等等)

答案 9 :(得分:0)

我偷了Yuliy和starblue(upvote他们)的答案

除了O(1)

之外,暂停是最快的
lottonumbers == mynumbers;

排序是O(nlog2n)

Bucketsort是一种O(n)算法。

所以你需要做的就是做两次(一次用于你的数字,一次用于目标集),如果数字加起来,那么它们就匹配了。 任何类型的排序都是额外的开销,在这种情况下是不必要的。

array[10] digits;
while(targetnum > 0)
{
    short currDig = targetnum % 10;
    digits[currDig]++;
    targetnum = targetnum / 10;
}
while(mynum > 0)
{
    short myDig = mynum % 10;
    digits[myDig]--;
    mynum = mynum / 10;
}
for(int i = 0; i < 10; i++)
{
   if(digits[i] == 0)
      continue;
   else
     //FAIL TO MATCH
}

不是最漂亮的代码,我承认。

答案 10 :(得分:0)

创建一个包含10个整数的数组[0 .. 9]。

将每个元素初始化为不同的素数

将产品设为1。

使用数字中的每个数字,下标到数组中, 拉出素数,然后乘以它。

这为您提供了一个独立的数字顺序表示。

对另一个号码执行相同的操作。

如果唯一表示匹配,则原始数字匹配。

答案 11 :(得分:0)

如果不允许重复数字(不确定是否是这种情况),则使用10位二进制数。最高有效位表示数字9,LSB表示数字0.依次处理每个数字并翻转您找到的每个数字的相应位

所以1689年将是:1101000010

和9816也将是:1101000010

如果你是胜利者,则XOR或减法将离开0

这只是一种简单的分组形式

答案 12 :(得分:0)

只是为了好玩,在正常之外思考,而不是排序和其他方式,做删除事情。如果结果字符串为空,则表示您有胜利者!

    Dim ticket As String = "1324"
    Dim WinningNumber As String = "4321"

    For Each s As String In WinningNumber.ToCharArray
        ticket = Replace(ticket, s, "", 1, 1)
    Next

    If ticket = "" Then MsgBox("WINNER!")
    If ticket.Length=1 then msgbox "Close but no cigar!"

这也适用于重复数字..

答案 13 :(得分:-1)

一个可爱的解决方案是使用Zobrist hashing的变体。 (是的,我知道它有点矫枉过正,也有概率,但嘿,这是“聪明的”。)

将十元素数组a[0..9]初始化为随机整数。然后,对于每个数字d[],计算a[d[i]]的总和。如果数字包含相同的数字,则结果数字将相等; 具有高概率(在有多少可能的整数中约为1),反之亦然。

(如果您知道总共最多有10位数字,那么您可以使用固定数字1,10,100,...而不是随机数字来保证成功。这是不是太多的桶分类很多伪装。)