给定列表[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)
。
我们可以做得更好吗?
答案 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>
a_w + a_x
作为键,w, x
作为值。使用n-1
元素预填充此队列,其中x = 0且w = 1 .. n-1。(sum, w, x)
并将元素(a_w + a_x_plus_1, w, x+1)
放入队列(但在x&gt; = w时不放置元素)。当从队列中删除的两个连续元素具有相同的总和时停止。答案 1 :(得分:3)
Evgeny的解决方案可以通过预处理原始数组进行简化,如下所示。
我们首先使用哈希表来计算原始数组中每个元素的频率。如果至少2个元素具有重复(其频率至少为2),或者如果元素出现频率至少为4,则答案为true
。否则,如果元素a
出现频率为2或3,我们将2a
添加到第二个哈希表,并用原始数组中的单个副本替换a
的所有副本。
然后在修改后的数组中,对于每对索引i
,j
和i < 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)。