我有一个元素{7,2,1}的数组,想法是做7 * 2 + 7 * 1 + 2 * 1,这基本上是这个算法:
a
其中n
是我有数字的数组,<br>
<br>
<h1>
table1
</h1><br>
<br>
<table id="example" class="display" width="100%" cellspacing="0">
<thead>
<tr>
<th>First name</th>
<th>Place</th>
<th>Order</th>
</tr>
</thead>
</table>
<br>
<br>
<h1>
table 2
</h1><br>
<br>
<table id="example2" class="display" width="100%" cellspacing="0">
<thead>
<tr>
<th>First name</th>
<th>Place</th>
<th>checkbox</th>
</tr>
</thead>
</table>
是元素的数量,我需要一个更有效的算法来做这个,我不知道怎么做,有人可以帮我一把吗?
谢谢!
答案 0 :(得分:9)
在一般情况下你可以做得更好。是时候做一些数学了。让我们来看看3元素版本,我们有:
ab + ac + bc
= 1/2 * (2ab + 2ac + 2bc)
= 1/2 * (2ab + 2ac + 2bc + a^2 + b^2 + c^2 - (a^2 + b^2 + c^2))
= 1/2 * ((a+b+c)^2 - (a^2 + b^2 + c^2))
那是:
int sum = 0;
int sum_sq = 0;
for (int i : arr) {
sum += i;
sum_sq += i*i;
}
int result = (sum*sum - sum_sq) / 2;
这是O(n)
次乘法,而不是O(n^2)
。在某些时候,这肯定比天真的实施更好。对于3个元素来说,它是否更好是我没有时间的。
答案 1 :(得分:6)
@ chux的建议主要是重新分配操作:
a i * a i + 1 + a i * a i + 2 + ... + a i * a n
- &GT;
a i *(a i + 1 + ... + a n )
结合避免不必要的重新计算(a i + 1 + ... + a n )项的部分和,通过利用每个不同于接下来是输入数组的一个元素的值。
这是一个带O(1)开销的一次通过实现:
int psum(size_t n, int array[n]) {
int result = 0;
int rsum = array[n - 1];
for (int i = n - 2; i >= 0; i--) {
result += array[i] * rsum;
rsum += array[i];
}
return result;
}
索引i
右侧的所有元素之和在变量rsum
中从迭代到迭代保持不变。没有必要在数组中跟踪它的各种值,因为我们只需要循环的一次迭代的每个值。
这与输入数组中的元素数量呈线性关系。您会看到操作的数量和类型与@ Barry的答案非常相似,但是不需要类似于他的最后一步,这样可以节省一些操作。
正如@Barry在评论中观察到的那样,迭代也可以在另一个方向上运行,同时跟踪右手部分的左手部分和。这将与@ chux的描述略有不同,但它依赖于完全相同的原则。
答案 2 :(得分:4)
进行1次传球,从[a]
的末尾走到前面,并在“右侧”形成所有元素的总和。
第二遍,多个a[i] * sum[i]
。
O(n)中。
long sum0(int a[], int n) {
long sum = 0;
for (int i = 0; i < n - 1; ++i)
for (int k = i + 1; k < n; ++k)
sum += a[i] * a[k];
return sum;
}
long sum1(int a[], int n) {
int long sums[n];
sums[n - 1] = 0;
for (int i = n - 2; i >= 0; i--) {
sums[i] = a[i+1] + sums[i + 1];
}
long sum = 0;
for (int i = 0; i < n - 1; ++i)
sum += a[i] * sums[i];
return sum;
}
void test(int a[], int n) {
long s0 = sum0(a, n);
long s1 = sum1(a, n);
if (s0 != s1) printf("%9ld %9ld\n", s0, s1);
}
void tests(int k) {
while (k--) {
int n = rand() % 10 + 2;
int a[n + 1];
for (int m = 0; m < n; m++)
a[m] = rand() % 256;
test(a, n);
}
}
int main() {
int a[3] = { 7, 2, 1 };
printf("%d\n", sum1(a, 3));
tests(1000000);
puts("Done");
}
事实证明,由于正在运行的sums[]
只需要1个位置,因此不需要sums
数组。这有效地使这个答案与其他答案相似
long sum1(int a[], int n) {
int long sums = 0;
long sum = 0;
for (int i = n - 2; i >= 0; i--) {
sums = a[i+1] + sums;
sum += a[i] * sums;
}
return sum;
}
答案 3 :(得分:4)
我们有(a + b + c + ...) 2 =(a 2 + b 2 + c 2 + ...)+ 2(ab + bc + ca + ...)
你想要总和S = ab + bc + ca + ...,它有O(n 2 )对(使用2个嵌套循环)
你可以做2个独立的循环,一个在O中计算P = a 2 + b 2 + c 2 + ... n)时间,另一个在O(n)时间内计算Q =(a + b + c + ...) 2 。然后取S =(Q - P)/ 2。