让我们说我已经猜到了一个乐透号码:
1689
并且彩票的工作方式是,只要数字与实际中奖彩票号码中的数字1:1匹配,数字的顺序无关紧要。
因此,1689号码将是一个中奖彩票号码:
1896,1698,9816等。
只要您的猜测中的每个数字都出现在目标数字中,那么您就赢了彩票。
我能用这种数学方法吗?
我用O(N ^ 2)循环解决了这个问题,检查每个数字与中奖彩票号码的每个数字(用模数分隔)。哪个好,它有效,但我想知道我能做的任何简洁的数学技巧。
例如,起初......我认为我可能会很棘手,只需要拿出两个数字中每个数字的总和和乘积,如果它们匹配,那么你就赢了。
^你觉得那会起作用吗?
然而,当我发现彩票猜测时,我很快就反驳了这一点:222,124有不同的数字,但产品和数量相同。
任何人都知道我可以使用的任何数学技巧来快速确定num1中的数字是否与num2中的数字相匹配而不管顺序如何?
答案 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,...而不是随机数字来保证成功。这是不是太多的桶分类很多伪装。)