两对数相同的数

Posted

技术标签:

【中文标题】两对数相同的数【英文标题】:Two pairs of numbers with same sum 【发布时间】:2012-10-03 12:49:29 【问题描述】:

给定一个列表[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)

我们可以做得更好吗?

【问题讨论】:

你想要一个布尔答案,如是,有一个匹配,还是你想要一个匹配列表? 布尔答案...“确定是否存在成对不同的索引” 【参考方案1】:

计算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(n2)。空间要求也是 O(n2)。

可以在 O(n) 空间中执行相同的操作,但需要 O(n2 * log(n)) 时间,但算法稍作修改:Sum-subset with a fixed subset size:

    对列表进行排序。 对元素使用优先级队列,包含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 >= w 时不要放入元素)。当从队列中移除的两个连续元素的总和相同时停止。 要处理重复项,可以比较两个连续元素的 w、x,它们的总和相等。但是使用 krjampani 的预处理思想更容易。如果排序列表包含两对重复项或单个元素重复 4 次,则成功。否则重复的值不会超过一个;在列表中只保留它的单个实例,并将其双倍值与一对“特殊”索引一起添加到优先级队列中:(2a, -1, -1)。

【讨论】:

但是你怎么知道索引是否成对不同? @John:通过在你的循环中构建。不要循环i in 1..n, j in 1..n,而是循环i in 1..n-1, j in i..n 是的,但我们希望 w,x,y,z 成对不同。 @John:在哈希图中插入索引(总和是键,索引列表是值),第二步过滤掉所有匹配的索引。 @Imposter:如果 O(n^2) 空间不可接受,则答案中提到了其他算法。【参考方案2】:

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

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

【讨论】:

【参考方案3】:

Evgeny 的解决方案可以通过如下预处理原始数组得到一些简化。

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

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

【讨论】:

以上是关于两对数相同的数的主要内容,如果未能解决你的问题,请参考以下文章

算法编程题积累——腾讯笔试"有趣的数字“问题

[bzoj3992][SDOI2015]序列统计——离散对数+NTT

奇数次的数?

给逆序对数求原数组

给逆序对数求原数组

给逆序对数求原数组