第二种算法是如何变得比第一种算法更高效的?在第二种方法中,子阵列的右侧是如何移动的

How has the second algorithm become more efficient than the first one and how is the right side of the subarray moving in the second algorithm?

本文关键字:算法 二种 阵列 移动 何移动 何变得 一种 高效 方法      更新时间:2024-03-28

问题-给定一个n个数字的数组,我们的任务是计算最大子数组和,即大堆当数组中可能存在负值时,问题就很有趣了。数组={-1,2,4,-3,5,2,-5,2}。

第一种算法-

int best = 0;
for (int a = 0; a < n; a++) {
for (int b = a; b < n; b++) {
int sum = 0;
for (int k = a; k <= b; k++) {
sum += array[k];
}
best = max(best,sum);
}
}
cout << best << "n"; 

第二种算法-

int best = 0;
for (int a = 0; a < n; a++) {
int sum = 0;
for (int b = a; b < n; b++) {
sum += array[b];
best = max(best,sum);
}
}
cout << best << "n";

这就是书中所说的-通过从算法1中删除一个循环,可以很容易地提高算法1的效率子阵列移动。

在第二种算法中,子阵列的右端是如何移动的,有人能向我解释一下吗?

第一个版本对从索引a到索引b的子数组的所有子数组和进行强力比较,让我们将这些子数组和称为subsum(a,b)

第二个版本也是相当暴力的,但使用了subsum(a,b+1) == subsum(a,b) + array[b+1]

换句话说:要知道第一个元素(比如10元素(的和,可以使用之前计算的第一个9元素的和。如果你想用笔和纸来解决这个问题,这将是显而易见的,但第一个版本并没有做到这一点。相反,第一个版本对于ab的所有组合都有两个嵌套循环,并且总是以新的sum = 0开始,这相当浪费。


只考虑第一个版本的外循环:

for (int a = 0; a < n; a++) {
for (int b = a; b < n; b++) {
int sum = 0;
// ...
}
}

这里CCD_ 10计算CCD_。

在第二个版本中:

int best = 0;
for (int a = 0; a < n; a++) {
int sum = 0;
for (int b = a; b < n; b++) {
sum += array[b];
best = max(best,sum);
}
}

外循环负责在不同的"时间"启动子阵列;左端";。而内环";移动";";右端";。

内环体计算CCD_ 12和内环的下一次迭代"CCD_;移动";13到下一个索引以使用上述关系式计算CCD_ 14:CCD_。由于CCD_ 16固定在内循环中;移动右端";。