最大连续和问题
最大连续和问题。给出一个长度为 n 的序列
A1,A2,…,An ,求最大连续和。换句话说,要求找到 1≤i≤j≤n ,使得 Ai+Ai+1+...+Aj 尽量大。
时间复杂度为 n3 的算法
LL maxConSumN3(LL *a, LL n) {
tot = 0;
conSum = -INF;
for(LL i = 0; i < n; i++) {
for(LL j = i; j < n; j++) {
LL sum = 0;
for(LL k = i; k <= j; k++) {
sum += a[k];
tot++;
}
if(sum > conSum) {
conSum = sum;
}
}
}
return conSum;
}
时间复杂度为 n2 的算法
LL maxConSumN2(LL *a, LL n) {
tot = 0;
conSum = -INF;
for(LL i = 0; i < n; i++) {
LL sum = 0;
for(LL j = i; j < n; j++) {
sum += a[j];
tot++;
if(sum > conSum) {
conSum = sum;
}
}
}
return conSum;
}
时间复杂度为 nlog2n 的算法
// 采用分治法
// 对半划分
// 递归求解左半边和右半边的最大连续和
// 递归边界为left=right
// 求解左右连接部分的最大连续和
// 合并子问题:取三者最大值
LL division(LL *a, LL lef, LL righ) {
// 递归边界
if(lef == righ) {
return a[lef];
}
LL center = lef + (righ - lef) / 2;
// 左半边最大连续和
LL maxLeftSum = division(a, lef, center);
// 右半边最大连续和
LL maxRightSum = division(a, center + 1, righ);
// 左连接部分最大和
LL maxLeftConSum = -INF;
LL leftConSum = 0;
for(LL i = center; i >= lef; i--) {
leftConSum += a[i];
tot++;
if(leftConSum > maxLeftConSum) {
maxLeftConSum = leftConSum;
}
}
// 右连接部分最大和
LL maxRightConSum = -INF;
LL rightConSum = 0;
for(LL i = center + 1; i <= righ; i++) {
rightConSum += a[i];
tot++;
if(rightConSum > maxRightConSum) {
maxRightConSum = rightConSum;
}
}
return max(max(maxLeftSum, maxRightSum), maxLeftConSum + maxRightConSum);
}
LL maxConSumNLogN(LL *a, LL n) {
return division(a, 0, n - 1);
}
时间复杂度为
n
的算法
LL maxConSumN(LL *a, LL n) {
conSum = -INF;
LL sum = 0;
tot = 0;
for(int i = 0; i < n; i++) {
sum += a[i];
tot++;
if(sum < 0) {
sum = 0;
}
if(sum > conSum) {
conSum = sum;
}
}
return conSum;
}
测试主程序
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const LL INF = 100000000;
// 总执行次数
LL tot;
// 最大连续和
LL conSum;
// 求最大连续和问题
// n^3的算法
LL maxConSumN3(LL *a, LL n) {
tot = 0;
conSum = -INF;
for(LL i = 0; i < n; i++) {
for(LL j = i; j < n; j++) {
LL sum = 0;
for(LL k = i; k <= j; k++) {
sum += a[k];
tot++;
}
if(sum > conSum) {
conSum = sum;
}
}
}
return conSum;
}
// n^2的算法
LL maxConSumN2(LL *a, LL n) {
tot = 0;
conSum = -INF;
for(LL i = 0; i < n; i++) {
LL sum = 0;
for(LL j = i; j < n; j++) {
sum += a[j];
tot++;
if(sum > conSum) {
conSum = sum;
}
}
}
return conSum;
}
// nlogn的算法
// 采用分治法
// 对半划分
// 递归求解左半边和右半边的最大连续和
// 递归边界为left=right
// 求解左右连接部分的最大连续和
// 合并子问题:取三者最大值
LL division(LL *a, LL lef, LL righ) {
// 递归边界
if(lef == righ) {
return a[lef];
}
LL center = lef + (righ - lef) / 2;
// 左半边最大连续和
LL maxLeftSum = division(a, lef, center);
// 右半边最大连续和
LL maxRightSum = division(a, center + 1, righ);
// 左连接部分最大和
LL maxLeftConSum = -INF;
LL leftConSum = 0;
for(LL i = center; i >= lef; i--) {
leftConSum += a[i];
tot++;
if(leftConSum > maxLeftConSum) {
maxLeftConSum = leftConSum;
}
}
// 右连接部分最大和
LL maxRightConSum = -INF;
LL rightConSum = 0;
for(LL i = center + 1; i <= righ; i++) {
rightConSum += a[i];
tot++;
if(rightConSum > maxRightConSum) {
maxRightConSum = rightConSum;
}
}
return max(max(maxLeftSum, maxRightSum), maxLeftConSum + maxRightConSum);
}
LL maxConSumNLogN(LL *a, LL n) {
return division(a, 0, n - 1);
}
// n的算法
LL maxConSumN(LL *a, LL n) {
conSum = -INF;
LL sum = 0;
tot = 0;
for(int i = 0; i < n; i++) {
sum += a[i];
tot++;
if(sum < 0) {
sum = 0;
}
if(sum > conSum) {
conSum = sum;
}
}
return conSum;
}
int main() {
LL a[] = {-2, 3, 4, 5, -6, 7, -1, 2, 6};
cout << "时间复杂度为N^3的算法:" << maxConSumN3(a, 9);
cout << "\t 计算次数为:" << tot << endl;
cout << "时间复杂度为N^2的算法:" << maxConSumN2(a, 9);
cout << "\t 计算次数为:" << tot << endl;
tot = 0;
cout << "时间复杂度为NLogN的算法:" << maxConSumNLogN(a, 9);
cout << "\t 计算次数为:" << tot << endl;
cout << "时间复杂度为N的算法:" << maxConSumN(a, 9);
cout << "\t\t 计算次数为:" << tot << endl;
return 0;
}
输出结果为
时间复杂度为N^3的算法:20 计算次数为:165
时间复杂度为N^2的算法:20 计算次数为:45
时间复杂度为NLogN的算法:20 计算次数为:29
时间复杂度为N的算法:20 计算次数为:9
Process returned 0 (0x0) execution time : 0.196 s
Press any key to continue.
算法竞赛中的时间复杂度选择
LL maxConSumN(LL *a, LL n) {
conSum = -INF;
LL sum = 0;
tot = 0;
for(int i = 0; i < n; i++) {
sum += a[i];
tot++;
if(sum < 0) {
sum = 0;
}
if(sum > conSum) {
conSum = sum;
}
}
return conSum;
}
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const LL INF = 100000000;
// 总执行次数
LL tot;
// 最大连续和
LL conSum;
// 求最大连续和问题
// n^3的算法
LL maxConSumN3(LL *a, LL n) {
tot = 0;
conSum = -INF;
for(LL i = 0; i < n; i++) {
for(LL j = i; j < n; j++) {
LL sum = 0;
for(LL k = i; k <= j; k++) {
sum += a[k];
tot++;
}
if(sum > conSum) {
conSum = sum;
}
}
}
return conSum;
}
// n^2的算法
LL maxConSumN2(LL *a, LL n) {
tot = 0;
conSum = -INF;
for(LL i = 0; i < n; i++) {
LL sum = 0;
for(LL j = i; j < n; j++) {
sum += a[j];
tot++;
if(sum > conSum) {
conSum = sum;
}
}
}
return conSum;
}
// nlogn的算法
// 采用分治法
// 对半划分
// 递归求解左半边和右半边的最大连续和
// 递归边界为left=right
// 求解左右连接部分的最大连续和
// 合并子问题:取三者最大值
LL division(LL *a, LL lef, LL righ) {
// 递归边界
if(lef == righ) {
return a[lef];
}
LL center = lef + (righ - lef) / 2;
// 左半边最大连续和
LL maxLeftSum = division(a, lef, center);
// 右半边最大连续和
LL maxRightSum = division(a, center + 1, righ);
// 左连接部分最大和
LL maxLeftConSum = -INF;
LL leftConSum = 0;
for(LL i = center; i >= lef; i--) {
leftConSum += a[i];
tot++;
if(leftConSum > maxLeftConSum) {
maxLeftConSum = leftConSum;
}
}
// 右连接部分最大和
LL maxRightConSum = -INF;
LL rightConSum = 0;
for(LL i = center + 1; i <= righ; i++) {
rightConSum += a[i];
tot++;
if(rightConSum > maxRightConSum) {
maxRightConSum = rightConSum;
}
}
return max(max(maxLeftSum, maxRightSum), maxLeftConSum + maxRightConSum);
}
LL maxConSumNLogN(LL *a, LL n) {
return division(a, 0, n - 1);
}
// n的算法
LL maxConSumN(LL *a, LL n) {
conSum = -INF;
LL sum = 0;
tot = 0;
for(int i = 0; i < n; i++) {
sum += a[i];
tot++;
if(sum < 0) {
sum = 0;
}
if(sum > conSum) {
conSum = sum;
}
}
return conSum;
}
int main() {
LL a[] = {-2, 3, 4, 5, -6, 7, -1, 2, 6};
cout << "时间复杂度为N^3的算法:" << maxConSumN3(a, 9);
cout << "\t 计算次数为:" << tot << endl;
cout << "时间复杂度为N^2的算法:" << maxConSumN2(a, 9);
cout << "\t 计算次数为:" << tot << endl;
tot = 0;
cout << "时间复杂度为NLogN的算法:" << maxConSumNLogN(a, 9);
cout << "\t 计算次数为:" << tot << endl;
cout << "时间复杂度为N的算法:" << maxConSumN(a, 9);
cout << "\t\t 计算次数为:" << tot << endl;
return 0;
}
时间复杂度为N^3的算法:20 计算次数为:165
时间复杂度为N^2的算法:20 计算次数为:45
时间复杂度为NLogN的算法:20 计算次数为:29
时间复杂度为N的算法:20 计算次数为:9
Process returned 0 (0x0) execution time : 0.196 s
Press any key to continue.
假设机器速度是每秒