两对数字相同的总和

时间:2012-10-12 16:43:08

标签: algorithm list integer

给定列表[a_1 a_2 ... a_n](不一定是不同的)整数,确定是否存在成对不同的索引w,x,y,z,使a_w + a_x = a_y + a_z

我知道一种方法是使用4级for循环,每一循环迭代其中一个索引。当我们得到相等的总和时,检查所有指数是否成对不同。如果是,请返回true。如果我们已经用尽所有可能性,请返回false。这有运行时间O(n^4)

我们可以做得更好吗?

3 个答案:

答案 0 :(得分:4)

计算a_w + a_x的所有可能值,将它们插入哈希表。将(a_w + a_x,w)和(a_w + a_x,x)插入第二个哈希表。

在将值插入第一个哈希表之前,请检查它是否已存在于表中。如果是,请检查第二个表格。如果(a_w + a_x,w)或(a_w + a_x,x)中的任何一个存在,请不要插入任何内容(我们有一个重复的元素)。如果这些对中都没有在第二个表中,我们得到了肯定的答案。

如果在处理完所有(w,x)对后,我们没有得到肯定答案,这意味着没有这样的成对不同的指数。

时间复杂度为O(n 2 )。空间要求也是O(n 2 )。

可以在O(n)空间中执行相同的操作,但是O(n 2 * log(n))时间可以使用此答案稍加修改的算法:Sum-subset with a fixed subset size:< / p>

  1. 对列表进行排序。
  2. 为元素使用优先级队列,其中包含a_w + a_x作为键,w, x作为值。使用n-1元素预填充此队列,其中x = 0且w = 1 .. n-1。
  3. 从此队列中反复弹出最小元素(sum, w, x)并将元素(a_w + a_x_plus_1, w, x+1)放入队列(但在x&gt; = w时不放置元素)。当从队列中删除的两个连续元素具有相同的总和时停止。
  4. 为了处理重复,可以比较具有相等和的两个连续元素的w,x。但是使用krjampani的预处理思想更容易。如果排序列表包含两对重复项或单个元素重复4次,则成功。否则不会重复单个值;只保留列表中的单个实例,并将其doubled值与“特殊”索引对一起添加到优先级队列中:(2a,-1,-1)。

答案 1 :(得分:3)

Evgeny的解决方案可以通过预处理原始数组进行简化,如下所示。

我们首先使用哈希表来计算原始数组中每个元素的频率。如果至少2个元素具有重复(其频率至少为2),或者如果元素出现频率至少为4,则答案为true。否则,如果元素a出现频率为2或3,我们将2a添加到第二个哈希表,并用原始数组中的单个副本替换a的所有副本。

然后在修改后的数组中,对于每对索引iji < j,我们将a_i + a_j添加到第二个哈希表并返回{{1}如果我们在此哈希表中找到重复的条目。

答案 2 :(得分:0)

如果你有8.5GB的内存(对于无符号整数更多,如果sum或indeces没有跨越整个int范围则更少),创建三个数组。首先每个可能的总和使用1位。它是结果的位图。其次,每个可能的总和使用32位。它记录索引j。第三,每个可能的总和使用1比特。它是一个位域,记录在当前迭代中是否遇到过这个和i - 每次迭代都将其归零。迭代i = 0 ... n和j = i + 1 ... n。对于每个总和,查看它是否在第一个位域中设置(如果之前遇到过)。如果是,则查看第二个数组中记录的索引是匹配i还是j(如果旧j匹配new i或new j)。如果不是,请检查第二个数组中的位是否已设置(如果它在当前迭代中设置,因此旧的i匹配new i)。如果不是,那你就匹配了! (旧的我将永远不会匹配旧的j或新的j,新的我永远不会匹配新的j。)退出。否则,记录所有三个数组中的总和并继续。

虽然它使用了价值40美元的内存(我喜欢现在:),但这可能比使用哈希映射和装箱要快得多。甚至可以为较大的n使用较少的内存。一个缺点是数据几乎永远不会在L2缓存中。但是尝试将JVM设置为使用大页面,因此至少TLB未命中也不会进入主内存。处理为o(n ^ 2),内存为o(1)。