如何解决第二种算法如何变得比第一种更有效,子阵列的右侧如何在第二种算法中移动?
问题 - 给定一个包含 n 个数字的数组,我们的任务是计算最大子数组和,即数组中连续值序列的最大可能和 大批。当数组中可能有负值时,这个问题很有趣。数组 = {-1,2,4,-3,5,-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 更高效。这可以通过在右端计算总和的同时实现 子阵移动。
第二个算法中子数组的右端如何移动,谁能给我解释一下?
解决方法
第一个版本对从索引 a
开始到索引 b
的子数组的所有子数组总和进行蛮力比较,我们称这些子数组总和为 subsum(a,b)
。
第二个版本也相当暴力,但使用了 subsum(a,b+1) == subsum(a,b) + array[b+1]
的事实。
换句话说:要知道第一个 say 10
元素的总和,您可以使用先前计算的第一个 9
元素的总和。如果你用笔和纸解决这个问题,这将是显而易见的,但第一个版本并没有这样做。相反,第一个版本对 a
和 b
的所有组合有两个嵌套循环,并且总是以新的 sum = 0
开头,这相当浪费。
只考虑第一个版本的外循环:
for (int a = 0; a < n; a++) {
for (int b = a; b < n; b++) {
int sum = 0;
// ...
}
}
此处 //...
计算 subsum(a,b)
。
在第二个版本中:
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);
}
}
外循环负责在不同的“左端”启动子数组。而内循环“移动”了“右端”。
内循环体计算subsum(a,b)
,内循环的下一次迭代“移动”b
到下一个索引以计算subsum(a,b)
,使用上述关系:{{1} }.因为subsum(a,b) == subsum(a,b-1) + array[b]
在内循环中是固定的,所以作者说的是“移动右端”。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。