下面给出几个思路。
1.暴力法
这个的时间复杂度是O(n^3),肯定超时。
我写这个的目的是引出一个优化for循环的地方。
#include<iostream>
#include<algorithm>
#define MAX 200002
using namespace std;
int a[MAX];
int main() {
int n;
cin >> n;
for (int i = 0; i < n; i++) {
scanf("%d", &a[i]);
}
int front = 0, rear = 0;//保存最优序列的起始与终止下标
int sum = 0;//最大子段和
int temp = 0;//每一趟的子段和
for (int i = 0; i < n; i++) {
for (int j = i; j < n; j++) {
temp = 0;
for (int k = i; k <= j; k++) {
temp += a[k];
}
if (temp > sum) {
sum = temp;
front = i;
rear = j;
}
}
}
cout << sum << endl;
return 0;
}
2.暴力法优化
优化后的复杂度为O(n^2),过了一部分。
#include<iostream>
#include<algorithm>
#define MAX 200002
using namespace std;
int a[MAX];
int main() {
int n;
cin >> n;
for (int i = 0; i < n; i++) {
scanf("%d", &a[i]);
}
int front = 0, rear = 0;//保存最优序列的起始与终止下标
int sum = 0;//最大子段和
int temp = 0;//每一趟的子段和
for (int i = 0; i < n; i++) {
temp = 0;
for (int j = i; j < n; j++) {
temp += a[j];
if (temp > sum) {
sum = temp;
front = i;
rear = j;
}
}
}
cout << sum << endl;
return 0;
}
3.分治法
这道题是我刚学数据结构时,看陈越老师的课,她一开始就讲的这道题,用的分治法。当时理解起来特别困难,现在经过了半年的学习,理解起来轻松多了。
分治法的思想就是将数组一分为二,有最大子段和的子段一定出现在子段1,子段2或者横跨两个子段。这样递归的解决问题。
#include<iostream>
#include<algorithm>
#define MAX 200200
using namespace std;
const int minn = -19260817;
int a[MAX];
int MaxSubSum(int left, int right) {
int sum = 0;
if (left == right) {//当划分到只有一个数的时候
sum = a[left];
}
else {
int center = (left + right) / 2;
int leftsum = MaxSubSum(left, center);
int rightsum = MaxSubSum(center + 1, right);
//下面是求横跨两个部分的子段和
//方法是从划分点center开始向左和向右寻找最大子段和
int s1 = minn;//左边
int temps1 = 0;
for (int i = center; i >= left; i--) {
temps1 += a[i];
if (temps1 > s1) {
s1 = temps1;
}
}
int s2 = minn;//右边
int temps2 = 0;
for (int i = center+1; i <=right; i++) {
temps2 += a[i];
if (temps2 > s2) {
s2 = temps2;
}
}
sum = s1 + s2;
if (sum < leftsum) {
sum = leftsum;
}
if (sum < rightsum) {
sum = rightsum;
}
}
return sum;
}
int main() {
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
cout << MaxSubSum(1, n) << endl;
return 0;
}
4.动态规划
动态规划要满足的条件之一是子问题最优,这道题只要一段序列是正的,那么这段序列就可能是最优子序列的一部分,但是一段序列是负数,那么这段序列就肯定不再最优子序列里面。
#include<iostream>
#include<algorithm>
#define MAX 200200
using namespace std;
const int minn = -19260817;
int a[MAX];
int main() {
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
int sum = minn, temp = 0;
for (int i = 1; i <= n; i++) {
if (temp > 0) {
temp += a[i];
}
else {
temp = a[i];
}
if (temp > sum) {
sum = temp;
}
}
cout << sum << endl;
return 0;
}