法一:O(n^3)
#include <stdio.h>
#include <stdlib.h>
int sub_Sum(int a[], int left, int right)
{
int i, temp_sum = 0;
for(i = left; i <= right; i++)
{
temp_sum += a[i];
}
return temp_sum;
}
int main()
{
int i, j, k, len;
int max_sum = 0, cur_sum = 0;
printf("Please input the length of the sequence: \n");
scanf("%d\n", &len);
int *a = (int *)malloc(len * sizeof(int));
for(i = 0; i < len; i++)
{
scanf("%d", &a[i]);
}
for(i = 0; i < len; i++)
{
for(j = i; j < len; j++)
{
for(k = i; k <= j; k++)
{
cur_sum += a[k];
}
if(cur_sum > max_sum)
max_sum = cur_sum;
cur_sum = 0;
}
}
printf("Max sum is : %d\n", max_sum);
max_sum = 0;
for(i = 0; i < len; i++)
{
for(j = i; j < len; j++)
{
cur_sum = sub_Sum(a, i, j);
if(cur_sum > max_sum)
max_sum = cur_sum;
cur_sum = 0;
}
}
printf("Max sum is : %d\n", max_sum);
free(a);
return 0;
}
法二:O(n^2)
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i, j, len;
int cur_sum = 0, max_sum = 0;
printf("Please input the length of the sequence : \n");
scanf("%d\n", &len);
int *a = (int *)malloc(len * sizeof(int));
for(i = 0; i < len; i++)
{
scanf("%d", &a[i]);
}
for(i = 0; i < len; i++)
{
//计算一次以i开始的最大和值
for(j = i; j < len; j++)
{
cur_sum += a[j];
if(cur_sum > max_sum)
{
max_sum = cur_sum;
}
}
cur_sum = 0;
}
printf("The max sum is: %d\n", max_sum);
free(a);
return 0;
}
法三:分治法O(nlogn)
分治的思想:最大子序列和可能出现在三处。或者整个出现在输入数据的左半部,或者整个出现右半部,或者跨越输入数据的中部从而占据左右两个半部分。前两种情况递归求解。第三种情况的最大和可以通过求出前半部分的最大和(包含前半部分的最后一个元素)以及后半部分的最大和(包含后半部分的第一个元素)而得到,然后将这两个和加在一起,求出三个值的最大值。
#include <stdio.h>
#include <stdlib.h>
int DivideAndConque_sum(int a[], int left, int right)
{
int i, j;
if(left == right)
{
if(a[left] > 0)
return a[left];
else
return 0;
}
int center = (left + right) / 2;
//每次递归返回时,该值为该字段的最终左最大子序列的和
int maxLeftSum = DivideAndConque_sum(a, left, center);
//每次递归返回时,该值为该字段的右最大子序列和
int maxRightSum = DivideAndConque_sum(a, center + 1, right);
//从中间向左扩展求子段的最大子序列和
int maxLeftBorderSum = 0, leftBorderSum = 0;
for(i = center; i >= left; i--)
{
leftBorderSum += a[i];
if(leftBorderSum > maxLeftBorderSum)
maxLeftBorderSum = leftBorderSum;
}
//从中间向右扩展求子段的最大子序列和
int maxRightBorderSum = 0, rightBorderSum = 0;
for(j = center + 1; j < right; j++)
{
rightBorderSum += a[j];
if(rightBorderSum > maxRightBorderSum)
maxRightBorderSum = rightBorderSum;
}
int tmp = maxLeftSum > maxRightSum ? maxLeftSum : maxRightSum;
if(tmp >= maxLeftBorderSum + maxRightBorderSum)
return tmp;
else
return maxLeftBorderSum + maxRightBorderSum;
}
int main()
{
int i, len;
printf("Please input the length of the sequence : \n");
scanf("%d", &len);
int *a = (int *)malloc(len * sizeof(int));
for(i = 0; i < len; i++)
{
scanf("%d", &a[i]);
}
printf("The max sub length is : %d\n", DivideAndConque_sum(a, 0, len));
return 0;
}
法四:动态规划O(n)
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i, len;
int curSum = 0, maxSum = 0;
printf("Input the length of the sequence: \n");
scanf("%d", &len);
int *a = (int *)malloc(len * sizeof(int));
for(i = 0; i < len; i++)
{
scanf("%d", &a[i]);
}
for(i = 0; i < len; i++)
{
curSum = curSum + a[i];
if(curSum > maxSum)
{
maxSum = curSum;
}
if(curSum < 0)
curSum = 0;
}
printf("The max length of the sequence is : %d\n", maxSum);
}