一开始就上最大子列和,的确不太友好…
法一:暴力 每次从头往后加
int maxsubsum1(int a[], int n)
{
for (int i = 0; i < n; i++)
{
for (int j = i; j < n; j++)
{
int this_sum = 0;
for (int k = i; k <= j; k++)
{
this_sum += a[k];
}
if (this_sum > max_sum)
{
max_sum = this_sum;
}
}
}
return max_sum;
}
复杂度很明显了,三层for循环 O(N^3)
法二:做了一点小小的改进 每次计算时,没必要从头往后加,只用在之前序列的末尾再加上下一个数就OK
int maxsubsum2(int a[], int n)
{
for (int i = 0; i < n; i++)
{
int this_sum = 0;
for (int j = i; j < n; j++)
{
this_sum += a[j];
}
if (this_sum > max_sum)
{
max_sum = this_sum;
}
}
return max_sum;
}
复杂度也很明显了,两个for循环,O(N^2)
注意:当发现算法时间复杂度为O(N^2)时,下意识改进为O(NlogN)
法三:分治(自己写没写出来,直接用给出的代码了)
基本思想:递归地对左边求最大子列->递归地对右边求最大子列和->求跨越中间求最大子列和->最后取最大的那个
int Max3(int A, int B, int C)
{ /* 返回3个整数中的最大值 */
return A > B ? A > C ? A : C : B > C ? B : C;
}
int DivideAndConquer(int List[], int left, int right)
{ /* 分治法求List[left]到List[right]的最大子列和 */
int MaxLeftSum, MaxRightSum; /* 存放左右子问题的解 */
int MaxLeftBorderSum, MaxRightBorderSum; /*存放跨分界线的结果*/
int LeftBorderSum, RightBorderSum;
int center, i;
if (left == right)
{ /* 递归的终止条件,子列只有1个数字 */
if (List[left] > 0) return List[left];
else return 0;
}
/* 下面是"分"的过程 */
center = (left + right) / 2; /* 找到中分点 */
/* 递归求得两边子列的最大和 */
MaxLeftSum = DivideAndConquer(List, left, center);
MaxRightSum = DivideAndConquer(List, center + 1, right);
/* 下面求跨分界线的最大子列和 */
MaxLeftBorderSum = 0; LeftBorderSum = 0;
for (i = center; i >= left; i--)
{ /* 从中线向左扫描 */
LeftBorderSum += List[i];
if (LeftBorderSum > MaxLeftBorderSum)
MaxLeftBorderSum = LeftBorderSum;
} /* 左边扫描结束 */
MaxRightBorderSum = 0; RightBorderSum = 0;
for (i = center + 1; i <= right; i++)
{ /* 从中线向右扫描 */
RightBorderSum += List[i];
if (RightBorderSum > MaxRightBorderSum)
MaxRightBorderSum = RightBorderSum;
} /* 右边扫描结束 */
/* 下面返回"治"的结果 */
return Max3(MaxLeftSum, MaxRightSum, MaxLeftBorderSum + MaxRightBorderSum);
}
int maxsubsum3(int List[], int N)
{ /* 保持与前2种算法相同的函数接口 */
return DivideAndConquer(List, 0, N - 1);
}
法四:在线处理
基本思想:当前子列的和如果为负,则将它抛弃。因为加上一个负数,只会使后面的数越加越小
详细讲解可以去看看视频,上面用动画显示出来,超级直观
int maxsubsum4(int a[], int n)
{
int this_sum = 0;
for (int i = 0; i < n; i++)
{
this_sum += a[i];
if (this_sum > max_sum)
{
max_sum = this_sum;
}
else if (this_sum < 0)
{
this_sum = 0;
}
}
return max_sum;
}
复杂度为O(N) 线性复杂度
例:
用了一下之前比赛学的代码,AC了:
#include <iostream>
#include <algorithm>
using namespace std;
const int inf = 0x7fffffff;
int num[100005];
int main()
{
int N;
cin >> N;
for (int i = 0; i<N; i++)
{
cin >> num[i];
}
int ans = -inf;
for (int i = 0; i<N; i++)
{
ans = max(ans, num[i]);
}
if (ans <= 0)
{
cout << 0 << endl;
}
else
{
int sum = 0;
for (int i = 0; i<N; i++)
{
if (sum + num[i]<0)
{
sum = 0;
}
else
{
sum += num[i];
}
ans = max(ans, sum);
}
cout << ans << endl;
}
return 0;
}