给定一个带有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;
}
答案 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不是真正的完整数字。一般来说,你不应该使用双精度算术进行精确算术;改为使用任意精度有理数包。