四次实现的二次时间

时间:2014-02-27 19:51:58

标签: java arrays algorithm quadratic cubic

给定一个带有x元素的数组,我必须找到四个数字,当求和时,它们等于零。我还需要确定存在多少这样的总和。

所以立方时间涉及三个嵌套迭代器,所以我们只需要查找最后一个数字(使用二进制搜索)。

相反,通过使用笛卡尔积(X和Y的相同数组),我们可以将所有对及其总和存储在辅助数组中。因此,对于每个总和d,我们只需要查找-d

这看起来应该是(接近)二次时间:

public static int quad(Double[] S) {
  ArrayList<Double> pairs = new ArrayList<>(S.length * S.length);
  int count = 0;

  for (Double d : S) {
    for (Double di : S) {
      pairs.add(d + di);
    }
  }

  Collections.sort(pairs);

  for (Double d : pairs) {
    int index = Collections.binarySearch(pairs, -d);
    if (index > 0) count++; // -d was found so increment
  }

  return count;
}

x为353(对于我们特定的数组输入),解决方案应为528,但我只使用此解决方案找到257。对于我们的立方时间,我们能够找到所有528个4和

public static int count(Double[] a) {
  Arrays.sort(a);
  int N = a.length;
  int count = 0;

  for(int i = 0; i < N; i++) {
    for (int j = 0; j < N; j++) {
      for (int k = 0; k < N; k++) {
        int l = Arrays.binarySearch(a, -(a[i] + a[j] + a[k]));
        if (l > 0) count++;
      }
    }
  }
  return count;
}

双重精确度是否有机会?

编辑:讨论了使用BigDecimal代替double,但我们担心它会对性能产生影响。我们只处理数组中的353个元素,这对我们意味着什么呢?

EDITEDIT:如果我错误地使用BigDecimal,我道歉。我以前从未处理过图书馆。所以经过多次建议我尝试使用BigDecimal而不是

public static int quad(Double[] S) {
  ArrayList<BigDecimal> pairs = new ArrayList<>(S.length * S.length);
  int count = 0;

  for (Double d : S) {
    for (Double di : S) {
      pairs.add(new BigDecimal(d + di));
    }
  }

  Collections.sort(pairs);

  for (BigDecimal d : pairs) {
    int index = Collections.binarySearch(pairs, d.negate());
    if (index >= 0) count++;
  }

  return count;
}

因此,它找到了261个解决方案,而不是257个。这可能表明存在问题double,实际上我正在失去精确度。然而,261远离528,但我找不到原因。

LASTEDIT:所以我相信这是一个可怕而丑陋的代码,但它似乎也在起作用。我们已经尝试了,但是使用BigDecimal,我们现在能够获得所有528场比赛。

我不确定它是否足够接近二次时间,时间会证明 我告诉你怪物:

public static int quad(Double[] S) {
  ArrayList<BigDecimal> pairs = new ArrayList<>(S.length * S.length);
  int count = 0;

   for (Double d : S) {
    for (Double di : S) {
      pairs.add(new BigDecimal(d + di));
    }
  }

  Collections.sort(pairs);

  for (BigDecimal d : pairs) {
    BigDecimal negation = d.negate();
    int index = Collections.binarySearch(pairs, negation);
    while (index >= 0 && negation.equals(pairs.get(index))) {
      index--;
    }

    index++;

    while (index >= 0 && negation.equals(pairs.get(index))) {
      count++;
      index++;
    }
  }

  return count;
}

2 个答案:

答案 0 :(得分:1)

您应该在此处使用BigDecimal类而不是double,因为您的解决方案必须精确计算数组中浮点数的精确度,最多为0。如果你的一个十进制值是.1,那你就麻烦了。该二进制分数无法用double精确表示。以下面的代码为例:

double counter = 0.0;
while (counter != 1.0)
{
    System.out.println("Counter = " + counter);
    counter = counter + 0.1;
}

你会期望这次执行10次,但它是一个无限循环,因为计数器永远不会精确地为1.0。

示例输出:

Counter = 0.0
Counter = 0.1
Counter = 0.2
Counter = 0.30000000000000004
Counter = 0.4
Counter = 0.5
Counter = 0.6
Counter = 0.7
Counter = 0.7999999999999999
Counter = 0.8999999999999999
Counter = 0.9999999999999999
Counter = 1.0999999999999999
Counter = 1.2
Counter = 1.3
Counter = 1.4000000000000001
Counter = 1.5000000000000002
Counter = 1.6000000000000003

答案 1 :(得分:1)

当您搜索对或单个元素时,您需要计算多重性。也就是说,如果你在你的单数或对数组中找到了元素-d,那么你需要通过找到的匹配数增加计数,而不是仅增加1.这可能就是为什么你没有得到满搜索成对时的结果数。这可能意味着当您搜索单身人士时,匹配的数字528不是真正的完整数字。一般来说,你不应该使用双精度算术进行精确算术;改为使用任意精度有理数包。