共享至少一位数的对数

时间:2012-07-16 06:34:36

标签: algorithm

您获得了n个号码,您必须找到对数,以便在它们之间至少有一个数字。

EG。对于 5 号码:

2837 2818 654 35 931

答案: 6

这里的对是(2837,2818), (2837,35), (2837,931), (2818,931), (654,35), (35,931)

我的尝试:我采用的结构存储十进制数字,数字形式的数字和数字中的数字

现在,对于每个号码,我散列数字包含索引 0-9 ,并检查所有后续数字是否已存在任何数字。

我的尝试是O(n^2),这很慢。还有其他算法可以更快地运行吗?

3 个答案:

答案 0 :(得分:12)

了解变量是什么以及常量是什么至关重要。

位数是常数(10)。所有数字组的数量也是如此(1024)。所有这些集合的数量也是如此(2 20 ,或大约一百万)。让我们利用这一点。

让我们尝试将输入预处理为大小恒定的数据结构中的“等效”表示(与输入大小无关)。无论我们如何处理该恒定大小的结构,定义为恒定时间操作,因此总运行时间仅由预处理阶段渐近确定。

数据结构

创建一个1024个整数的数组,每个桶(索引)对应一组数字;我们希望存储每个桶中具有该组数字的输入数字的数量。

例如,3606具有数字0,3和6,因此它将在桶2中计算 0 + 2 3 + 2 6 < / sup> = 73。

<强>算法

预处理很明显。取下一个数字(例如'3'),将其转换为其值(例如3),现在计算相应的位(例如1 << 3)并将其转换为(暂定) )桶索引变量;不同的数字位于不同的位,所以每个数字组合都有一个独特的桶,但我们摆脱了任何重复的数字。像这样循环直到遇到数字分隔符;在那时,存储桶索引是最终的,我们可以只增加存储桶,重置存储桶索引并跳到下一个数字。

就是这样。剩下的就是数数我们的羊。哎呀。对羊。

将每个存储桶与其他存储桶进行比较(但不是自身)。只要两个索引共享一个数字(这可以使用&运算符确定),将这两个存储桶的内容相乘,并将产品添加到全局维护的总和中。

将每个存储桶与自身进行比较,并仅将x * (x - 1) / 2添加到全局维护的总和中,其中x是存储桶的内容。

这笔钱是你的结果。

<强>性能

最坏情况:O(n)其中n是输入大小。

恒定因素也是有利的。我们需要每个数字或分隔符提供一些指令(以及RAM访问);恒定阶段检查一百万个桶对,在每对上花费类似于另一个少量指令(不需要RAM访问,数据结构非常紧凑)。这很快。

理论家会说这是作弊。我们假设输入长度没有上限(或者我们根本不能说渐近复杂度),但我们还假设我们可以将总输入长度放到整数变量中。哦,好吧。

更实用的程序员会注意到该算法在字母大小方面是指数级的。我们很幸运;如果我们的单词不是由数字组成,而是除了分隔符之外的任意字符,我们的单词仍然是渐近线性时间算法,但对于任何输入来说它都会非常慢,相比之下,一个天真的算法可以很容易地达到兆字节。一次输入。

答案 1 :(得分:0)

创建一个集合数组,每个数字一个。

迭代你的数字并将每个数字放在它包含的数字中。

迭代所有10个集合,并将集合中的每个元素与同一集合中的所有其他元素组合在一起。 (或者如果你不想在你的结果中使用(a,b)和(b,a),那么所有其他元素都比自身大。

我认为这仍然是O(n ^ 2),但可以使用fork join方法很好地并行化。

<强>更新

刚刚意识到你只想要结果的数量。因此,对于所有集合,这将是大小* size-1的总和。因为插入一个集合并获得它的大小应该是线性的(我认为)这实际上可能是O(n)

<强> anotherupdate

如果您的数字不同而且您只对数量感兴趣,那么您甚至不需要套数,而只需要一个计数器。

不起作用 来自评论:

Consider 1st pair in above questions test case (2837,2818), this will put first number in set containing digit 2 and 8 and same for 2818 now they are to be counted as one but counting in 2 and 8 will count it twice. I hope you understand what I am trying to say...

所以这种做法不起作用......我想这对其他人来说可能是有价值的。

答案 2 :(得分:0)

首先,我注意到普通数字的位置并不重要。

在这种情况下,我用哈希表绘制了一个小算法:形成10个箱,每个数字一个。然后,对于每个数字,(唯一地)将与其具有的每个数字对应的每个二进制数中的数字的ID。该操作是O(n * k),k是数字的位数。最后,要形成所有对,请在每个箱内取成对数。为了消除可能的双重,用a排列每对(a,b)

我认为最坏的情况实际上是O(n ^ 2);事实上,我确实认为这一步必须具有O(n ^ 2)的复杂度,因为你想要获取所有对(最大n *(n + 1)/ 2)。所以最后的复杂性实际上是二次的。