Algorithm 两个数字加起来等于三

Algorithm 两个数字加起来等于三,algorithm,language-agnostic,Algorithm,Language Agnostic,给定一个整数数组[a1 a2…an],不一定是不同的,给出一个算法,如果存在不同的索引i,j,k,则返回“yes”,否则返回“no” 有没有一种方法能比暴力更快地做到这一点,暴力需要O(n^3)?是的 第一步:对数组进行排序 然后你用一种聪明的方式浏览你的指数。一个明智的方法是选择 a0+a1 a0+a2 a0+a3 a0+a(n-1) a1+a(n-1) a1+a(n-2) 这里的Smart意味着两个连续的测试指数对不能彼此太远 对于第一个,aO+a1您可以通过在O(logn)中进行二进

给定一个整数数组
[a1 a2…an]
,不一定是不同的,给出一个算法,如果存在不同的
索引
i,j,k
,则返回“yes”,否则返回“no”

有没有一种方法能比暴力更快地做到这一点,暴力需要O(n^3)?

是的

第一步:对数组进行排序

然后你用一种聪明的方式浏览你的指数。一个明智的方法是选择

  • a0+a1
  • a0+a2
  • a0+a3
  • a0+a(n-1)
  • a1+a(n-1)
  • a1+a(n-2)
这里的Smart意味着两个连续的测试指数对不能彼此太远

对于第一个,
aO+a1
您可以通过在
O(logn)
中进行二进制搜索来查找是否存在
k
这样的
a0+a1=ak

对于以下情况,假设测试对与前一对接近,这意味着如果存在
k'
使得
ai+aj=ak'
那么
k'
必须接近
k
。您可能可以从
k
进行线性搜索,直到
k'
ai+aj
对匹配或变得太大/太小。在一般情况下,这将花费
O(1)

由于您最多只能测试
n^2
对,因此整个算法是
O(n^2)

  • 建立一个列表,列出所有可能的和ai+aj:O(n^2)。
    列表的大小为n^2

  • 然后将该列表与数组进行比较,以查看是否存在任何相似之处:

    • 首先对每个列表进行排序:O((n^2)log(n^2))+O(nlogn)
    • 遍历它们以查找任何匹配项:O(n^2)
总计:每个alestanis评论0((n^2)log(n^2))(=0((n^2)log(n))

编辑:我忘记了明确的要求,但这不会改变结果。
首先,我保证=j、 在步骤1中构建所有和的列表时,只需排除i==j。
第二,我保证=k和j=k、 排序前,用索引i、j标记每个和,用索引k标记每个原始值。

然后在最后一步中,当您找到任何匹配项时,检查标记的索引是否不同。

下面的python代码实现了一种类似于alestanis所述的方法,并且类似于Daniel Le所提到的中给出的二次算法。对于大的一致随机正整数,所述的O(n^2)复杂性似乎成立。(将执行的k平均增加约(n^2)/4倍的内部搜索循环)在旧AMD Athlon 5000处理器上的linux下运行的定时示例的输出首先出现,然后是代码

0.002519    N 50    NN 2500     ops 607     NN/ops 4.1186   NN/t 992405.8   Matches 0
0.00752     N 100   NN 10000    ops 1902    NN/ops 5.2576   NN/t 1329794.2  Matches 0
0.035443    N 200   NN 40000    ops 10648   NN/ops 3.7566   NN/t 1128570.5  Matches 2
0.063056    N 400   NN 160000   ops 37403   NN/ops 4.2777   NN/t 2537427.4  Matches 33
0.176328    N 800   NN 640000   ops 163247  NN/ops 3.9204   NN/t 3629595.6  Matches 244
0.729919    N 1600  NN 2560000  ops 658122  NN/ops 3.8899   NN/t 3507238.7  Matches 2062
2.720713    N 3200  NN 10240000     ops 2535751     NN/ops 4.0383   NN/t 3763719.4  Matches 16178
11.07818    N 6400  NN 40960000     ops 10160769    NN/ops 4.0312   NN/t 3697358.2  Matches 128793
导入随机、对分、时间
五、 W,N,Nlim=500500000,506400
而N U[k]:
k+=1
ops+=1
如果U[k]==ai+aj:
#打印“匹配”,i,j,k,ai,aj,ai+aj,U[k]
匹配项+=1
如果ai+aj>bigsum:
打破
et=时间。时间()-t0
打印轮(et,6),“\tN',N”,\tNN',N*N”,\tops',ops,“\tNN/ops”,
打印轮(浮动(N*N)/ops,4),“\tNN/t”,轮(N*N/et,1),“\t匹配”,匹配
N*=2
代码可能应该按照维基百科的大纲重写;重写可能会清除一些令人尴尬的数组片数和无关的完成检查。

#包括
#include <cstdio>
#include <algorithm>
#include <vector>

using namespace std;

bool SUM3(vector<int> &v)
{
  sort(v.begin(), v.end());

  for (int i = 0; i < v.size(); ++i) {
    int j = 0, k = v.size() - 1;

    while (j < k) {
      int result = v[j] + v[k] - v[i];

      if (result < 0 || i == j) ++j;
      else if (result > 0) --k;
      else return true;
    }
  }

  return false;
}

int main()
{
  int a1[] = {25, 7, 9, 2, 4, 8, 10};
  vector<int> v1(a1, a1 + sizeof a1 / sizeof a1[0]);

  printf("%s\n", SUM3(v1) ? "true" : "false");

  int a2[] = {1, 2, 4};
  vector<int> v2(a2, a2 + sizeof a2 / sizeof a2[0]);

  printf("%s\n", SUM3(v2) ? "true" : "false");
  return 0;
}
#包括 #包括 使用名称空间std; 布尔SUM3(矢量和矢量) { 排序(v.begin(),v.end()); 对于(int i=0;i0)--k; 否则返回true; } } 返回false; } int main() { int a1[]={25,7,9,2,4,8,10}; 向量v1(a1,a1+sizeof a1/sizeof a1[0]); printf(“%s\n”,SUM3(v1)?“真”:“假”); int a2[]={1,2,4}; 向量v2(a2,a2+sizeof a2/sizeof a2[0]); printf(“%s\n”,SUM3(v2)?“真”:“假”); 返回0; }

此算法的复杂性为O(n^2)。

有一个n^2解决方案不需要排序,尽管它需要n^2额外的空间
O((n^2)log(n^2))
相当于
O((n^2)log(n))
好的,但是你怎么知道三个索引
i,j,k
是不同的呢?(见问题)