求数组中和的快速算法

2024-04-16

我正在寻找一种快速算法:

我有一个大小为 n 的 int 数组,目标是找到数组中的所有模式
x1, x2, x3 are different elements in the array, such that x1+x2 = x3

例如我知道有一个大小为 3 的 int 数组是[1, 2, 3]那么只有一种可能性:1+2 = 3(考虑1+2 = 2+1)

我正在考虑实现对和哈希图以使算法更快。 (我现在最快的还是O(n^2))

请分享您对这个问题的想法,谢谢


Edit:下面的答案适用于这个问题的一个版本,其中您只想要一个像这样加起来的三元组。当您想要所有这些时,由于可能至少有 O(n^2) 种可能的输出(如 ex0du5 所指出的),甚至在重复元素的病理情况下甚至是 O(n^3) 种,因此您不会击败基于散列的简单 O(n^2) 算法(从一个值映射到具有该值的索引列表)。


这基本上是3SUM问题 http://en.wikipedia.org/wiki/3SUM。如果没有潜在的无限大元素,最著名的算法大约是O(n^2),但我们只是证明了它不能比O(n lg n)对于大多数计算模型。

如果整数元素位于范围内[u, v],你可以做一个稍微不同的版本O(n + (v-u) lg (v-u))FFT http://en.wikipedia.org/wiki/Fast_Fourier_transform。我将描述一个过程,将这个问题转化为那个问题,在那里解决它,然后根据这个转化找出问题的答案。

我知道如何用FFT解决的问题是在数组中找到长度为3的算术序列:即一个序列a, b, c with c - b = b - a,或等价地,a + c = 2b.

不幸的是,转变的最后一步并没有我想要的那么快,但当我们到达那里时我会谈论这个。


让我们调用你的原始数组X,其中包含整数x_1, ..., x_n。我们想要找到索引i, j, k这样x_i + x_j = x_k.

  1. 找到最小值u和最大v of X in O(n)时间。让u' be min(u, u*2) and v' be max(v, v*2).

  2. 构造一个二进制数组(位串)Z长度v' - u' + 1; Z[i]为真,如果X或其双倍[x_1*2, ..., x_n*2]包含u' + i。这是O(n)初始化;只需遍历每个元素X并设置两个相应的元素Z.

    当我们构建这个数组时,我们可以将找到的任何重复项的索引保存到辅助列表中Y. Once Z已完成,我们只需检查2 * x_i对于每个x_i in Y。如果有的话,我们就完成了;否则重复项是无关紧要的,我们可以忘记Y。 (唯一稍微复杂的情况是如果0被重复;那么我们需要它的三个不同的副本才能得到解决方案。)

    现在,解决您的问题,即x_i + x_j = x_k,将出现在Z作为三个均匀分布的,因为一些简单的代数运算给我们2*x_j - x_k = x_k - 2*x_i。请注意,末尾的元素是我们特殊的双条目(来自2X),中间的一个是常规条目(来自X).

  3. Consider Z as a representation of a polynomial p, where the coefficient for the term of degree i is Z[i]. If X is [1, 2, 3, 5], then Z is 1111110001 (because we have 1, 2, 3, 4, 5, 6, and 10); p is then 1 + x + x2 + x3 + x4 + x5 + x9.

    Now, remember from high school algebra that the coefficient of xc in the product of two polynomials is the sum over all a, b with a + b = c of the first polynomial's coefficient for xa times the second's coefficient for xb. So, if we consider q = p2, the coefficient of x2j (for a j with Z[j] = 1) will be the sum over all i of Z[i] * Z[2*j - i]. But since Z is binary, that's exactly the number of triplets i,j,k which are evenly-spaced ones in Z. Note that (j, j, j) is always such a triplet, so we only care about ones with values > 1.

    We can then use a Fast Fourier Transform http://en.wikipedia.org/wiki/Fast_Fourier_transform to find p2 in O(|Z| log |Z|) time, where |Z| is v' - u' + 1. We get out another array of coefficients; call it W.

  4. 循环每个x_k in X。 (回想一下,我们想要的均匀分布的都集中在一个元素上X, not 2*X.)如果对应W对于该元素的两倍,即W[2*(x_k - u')], 是 1,我们知道它不是任何重要级数的中心,我们可以跳过它。 (如前所述,它只能是正整数。)

    否则,它可能是我们想要的进展的中心(所以我们需要找到i and j)。但不幸的是,它也可能是一个没有我们想要的形式的进展的中心。所以我们需要检查一下。循环其他元素x_i of X,并检查是否存在三元组2*x_i, x_k, 2*x_j对于一些j(通过检查Z[2*(x_k - x_j) - u'])。如果是这样,我们就有了答案;如果我们能完成所有的X如果没有命中,那么 FFT 只发现虚假答案,我们必须检查另一个元素W.

    因此,最后一步是 O(n * 1 + (x_k 的数量,其中 W[2*(x_k - u')] > 1 实际上不是解决方案)),这可能是O(n^2),这显然是不行的。应该有一种方法可以避免在输出中生成这些虚假答案W;如果我们知道任何适当的W系数肯定有答案,最后一步是O(n)一切都会好起来的。

    我认为可以使用稍微不同的多项式来做到这一点,但我还没有让它真正发挥作用。我再考虑一下......

部分基于这个答案 https://stackoverflow.com/a/1585303/344821.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

求数组中和的快速算法 的相关文章

  • C语言声明数组没有初始大小

    编写一个程序来操纵温度详细信息 如下所示 输入要计算的天数 主功能 输入摄氏度温度 输入功能 将温度从摄氏度转换为华氏度 独立功能 查找华氏度的平均温度 我怎样才能在没有数组初始大小的情况下制作这个程序 include
  • 如何仅使用单个数组在 JavaScript 中模拟调用堆栈

    我正在看维基百科页面 https en wikipedia org wiki Call stack在调用堆栈上 并尝试理解这个图像 据我所知 哈哈 const memory memory 0 3 top of stack pointer m
  • 使用 VBA 通过简单命令从非连续范围的并集获取值到数组中(无循环)

    我有以下任务 表面上很简单 使用 VBA 将电子表格上多个列的值复制到二维数组中 为了让生活更有趣 这些柱子并不相邻 但它们的长度都相同 显然 可以通过依次循环每个元素来做到这一点 但这看起来非常不优雅 我希望有一个更紧凑的解决方案 但我很
  • 包围一组点的多边形

    我有一组 S 点 2D 由 x 和 y 定义 我想找到 P 包围该组所有点的最小 含义 具有最少数量的点 多边形 P 是S 有没有已知的算法来计算这个 我在这个领域缺乏文化令人惊讶 感谢您的帮助 对于这个问题有很多算法 它被称为 最小边界框
  • 通过嵌套数组对象属性将数组映射到字符串数组

    拥有包含嵌套数组的对象数组 let arr name aaa inputs inputName input 1 groups groupName group a name bbb inputs inputName input 2 group
  • 用 C++ 生成 AST

    我正在用 C 制作一个解释器 到目前为止我已经有了词法分析器来生成标记 问题是我不确定如何生成 行走 解析树 我正在考虑使用数组数组来制作解析树 但我不确定如何以正确的顺序将标记实际插入到解析树中 我不确定是自上而下 左右还是自下而上 左右
  • 使用多级解决方案计算二维网格中的最近邻

    我有一个问题 在 x y 大小的网格中 我提供了一个点 并且我需要找到最近的邻居 在实践中 我试图在 pygame 中找到距离光标最近的点 该点跨越颜色距离阈值 计算如下 sqrt rgb1 0 rgb2 0 2 rgb1 1 rgb2 1
  • 异或交换可以扩展到两个以上的变量吗?

    我一直在尝试将异或交换扩展到两个以上的变量 例如n变量 但我没有得到比这更好的地方3 n 1 对于两个整型变量x1 and x2你可以像这样交换它们 swap x1 x2 x1 x1 x2 x2 x1 x2 x1 x1 x2 所以 假设你有
  • let/var 如何解决可变性? [复制]

    这个问题在这里已经有答案了 我没有任何问题 我只是想对有关可变性的问题进行一些澄清 在 Objective C 中我们会使用例如NSMutableArray得到一个可变数组和NSArray得到一个不可变的 我对两者的内部运作了解不多 但据我
  • 使用并集查找(又名不相交集)检测图是否是二分图

    我正在 Spoj 上做一个问题 基本上可以简化为检测图是否是二分图 我正在尝试使用 dfs 为图表着色 但它太慢了 有人评论这个 没有 bfs 没有 dfs 没有二部图 简单的并查集就可以做到 确实速度很快 提示 1 偶数长度的环不会影响两
  • 直接选择排序与交换选择排序

    有什么区别直接选择排序 vs 交换选择排序 今天我陷入了一场争论 我的教授在他的讲义中使用了这两个术语 维基百科和任何教科书或网站都会为您提供的选择排序就是他所说的 交换选择排序 我以前从未听说过 交换选择排序 这个术语 仅 选择排序 并且
  • 如何使用 PHP 查找目录中的前 5 个文件?

    如何使用 PHP 列出按字母顺序排序的目录中的前 5 个文件或目录 Using scandir array slice array filter scandir path to dir is file 0 5 The array filte
  • Angular 4 显示其中的数据

    我不喜欢从 API 返回到我的 Angular 4 应用程序的数据 这是 JSON 的示例 我不关心美元 但这是我正在处理的数据类型 最终目标是在页面上展示 Coin Price BTC 4 281 28 ETH 294 62 etc JS
  • 如何从一维数组和静态字符串创建对象

    我想要一个像 var obj ABC name true dob true CDE name true dob true EFG name true dob true CBA name true dob true XYZ name true
  • 具有多个谓词的 C++11 算法

    功能如std find if来自algorithmheader 确实很有用 但对我来说 一个严重的限制是我只能为每次调用使用 1 个谓词count if 例如给定一个像这样的容器std vector我想同时应用相同的迭代find if 多个
  • 高效创建抗锯齿圆形蒙版

    我正在尝试创建抗锯齿 加权而不是布尔 圆形掩模 以制作用于卷积的圆形内核 radius 3 no of pixels to be 1 on either side of the center pixel shall be decimal a
  • 迭代任意大小的子集

    我可以迭代大小为 1 的子集 for int a 0 a lt size a 或大小为 2 的子集 for int a1 0 a1 lt size a1 for int a2 a1 1 a2 lt size a2 or 3 for int
  • Python:结构体和数组与 ctypes 中的类似功能

    Python 提供了以下三个处理 C 类型以及如何处理它们的模块 struct https docs python org 3 library struct html对于 C 结构体 array https docs python org
  • 归并排序中递归树的高度log(n)+1是怎么来的

    我按照 stackoveflow 的建议阅读了一些问题和答案 我正在遵循 cormen 的 算法简介 一书进行自学 那本书里已经解释得很清楚了 但唯一没有解释的是如何在合并排序分析中计算树的高度 如果在后面的章节中对此进行解释的话 我仍然在
  • 大数据使用什么数据结构

    我有一个包含一百万行的 Excel 工作表 每行有 100 列 每行代表一个具有 100 个属性的类的实例 列值是这些属性的值 哪种数据结构最适合在这里使用来存储数百万个数据实例 Thanks 这实际上取决于您需要如何访问这些数据以及您想要

随机推荐