最大子段和问题
给定n个整数(可能为负整数)组成的序列,
求该序列的子段和的最大值。
当所有整数均为负整数时定义其最大子段和为0(相当于取空子段)。
例如:求矩阵序列a[]={-2,1,-4,13,-5,-2}的最大子段和。
结果应为20。
这篇博客主要用于本人之后的复习,如果能帮到读者那最好。
最大子段和问题的简单算法——O(n^2)
int MaxSum(int n, int *a, int &besti, int &bestj) //双重循环求解
{
int sum = 0;
for (int i = 0; i < n; i++)
{
int thissum = 0;
for (int j = i; j < n; j++)
{
thissum += a[j];
if (thissum > sum) //找到了更大的子段和
{
sum = thissum;
besti = i;
bestj = j;
}
}
}
return sum;
}
最大子段和问题的分治算法——O(nlogn)
int MaxSubSum(int *a, int left, int right) //分治法算法
{
int sum = 0;
if (left == right) //递归的最里层
sum = a[left] > 0 ? a[left] : 0; //如果最小单元为负数,那最大子段和为空子段,为0
else
{
int mid = (left + right) / 2;
int leftsum = MaxSubSum(a, left, mid); //左子段的最大子段和
int rightsum = MaxSubSum(a, mid + 1, right); //右子段的最大子段和
int sum1 = 0, lefts = 0;
for (int i = mid; i >= left; i--) //这里从右到左是为了从mid向左向右延伸,获取中间的子段和大小
{
lefts += a[i];
if (lefts > sum1)
sum1 = lefts;
}
int sum2 = 0, rights = 0;
for (int i = mid + 1; i <= right; i++)
{
rights += a[i];
if (rights > sum2)
sum2 = rights;
}
sum = sum1 + sum2; //左右最大子段和相加
if (sum < leftsum)
sum = leftsum;
if (sum < rightsum)
sum = rightsum; //三者比较取最大值作为该段的最大子段和sum
}
return sum;
}
最大子段和问题的动态规划算法——O(n)
int MaxSum2(int n, int *a) //动态规划算法
{
int sum = 0, temp = 0;
for (int i = 0; i < n; i++)
{
if (temp > 0)
temp += a[i];
else
temp = a[i];
if (temp > sum)
sum = temp;
}
return sum;
}
在这个问题中,动态规划算法的时间复杂度相对最低。
最后放上main函数部分。
int main()
{
int a[] = {-2, 11, -4, 13, -5, -2};
int besti = 0, bestj = 0;
cout << "sum= " << MaxSum(6, a, besti, bestj) << endl;
cout << besti << " " << bestj << endl;
cout << "sum= " << MaxSubSum(a, 0, 5) << endl;
cout << "sum= " << MaxSum2(6, a) << endl;
return 0;
}