题目:最大子列和
问题描述:在一个一维数组中找到一个连续的子数列,使该子数列的和最大,输出该和的值
输入:数组元素个数n,数组各元素
输出:最大子列和
(以int类型数组为例)
目录
方法1
时间复杂度:O(N³)
int maxsubsetsum1(int A[], int n)
{
int thissum, maxsum = A[0];//注意:maxsum的初值应当是其可能的任一值,但不可随意赋值
for (int i = 0; i < n; i++)
{
for(int j = i; j < n; j++)
{
thissum = 0;
for (int k = i; k <= j; k++)
{
thissum += A[k];
}
maxsum = maxsum >= thissum ? maxsum : thissum;
}
}
return maxsum;
}
方法2
时间复杂度:O(N²)
nt maxsubsetsum2(int A[], int n)
{
int thissum, maxsum = A[0];//注意:maxsum的初值应当是其可能的任一值,但不可随意赋值
for (int i = 0; i < n; i++)
{
thissum = 0;
for (int j = i; j < n; j++)
{
thissum += A[j];
maxsum = maxsum >= thissum ? maxsum : thissum;
}
}
return maxsum;
}
方法3:分治法
时间复杂度:O(N logN)
int maxsubsetsum3(int A[], int l, int r)
{
if (l == r) //分到最后一层,直接返回
{
return A[l];
}
int mid = (l + r) / 2; //取中间位置
int maxleftsum = maxsubsetsum3(A, l, mid); //求左组的最大子列和
int maxrightsum = maxsubsetsum3(A, mid + 1, r); //求右组的最大子列和
//该子列元素同时存在于左组和右组,即该子列中含有A[mid]和A[mid+1]
//注意:初值应当是其可能的任一值,但不可随意赋值
int maxleftmidsum = A[mid];
int leftmidsum = 0;
int maxrightmidsum = A[mid + 1];
int rightmidsum = 0;
for (int i = mid; i >= l; i--) //该子列左部分的和
{
leftmidsum += A[i];
maxleftmidsum = maxleftmidsum < leftmidsum ? leftmidsum : maxleftmidsum;
}
for (int i = mid + 1; i <= r; i++) //该子列右部分的和
{
rightmidsum += A[i];
maxrightmidsum = maxrightmidsum < rightmidsum ? rightmidsum : maxrightmidsum;
}
return max3(maxleftsum, maxrightsum , maxleftmidsum + maxrightmidsum);//左组最大子列和,右组最大子列和,包含A[mid]和A[mid+1]的最大子列和
}
int max3(int a, int b, int c) //求三者中的最大值
{
if (a < b)a = b;
if (a < c)a = c;
return a;
}
方法4:在线处理
时间复杂度:O(N)
int maxsubsetsum4(int A[], int n)
{
int thissum=0, maxsum=A[0];
for (int i = 0; i < n; i++)
{
thissum += A[i];
if (thissum > maxsum)
{
maxsum = thissum;
}
else if (thissum < 0)
{
thissum = 0;
}
}
return maxsum;
}
检验
最后,加上main函数,输入数据,调用函数进行检验
int main()
{
int n;
while (scanf("%d", &n) == 1 && n != 0)//当输入n为0时结束程序
{
int num[100];
for (int i = 0; i < n; i++)
{
cin >> num[i];
}
printf("maxsubsetsum1= %d\n", maxsubsetsum1(num, n));
printf("maxsubsetsum2= %d\n", maxsubsetsum2(num, n));
printf("maxsubsetsum3= %d\n", maxsubsetsum3(num, 0, n - 1));
printf("maxsubsetsum4= %d\n", maxsubsetsum4(num, n));
}
return 0;
}
一个很好的方法是:当用多种算法解决同一问题时,若输出一致,则方法大抵正确
注意:要选用一些刁钻数据(如全为正数、全为负数、正数负数都有)
附上运行结果:
完整代码
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
using namespace std;
int maxsubsetsum1(int A[], int n);
int maxsubsetsum2(int A[], int n);
int maxsubsetsum3(int A[], int l, int r);
int maxsubsetsum4(int A[], int n);
int max3(int a, int b, int c);
int main()
{
int n;
while (scanf("%d", &n) == 1 && n != 0)//当输入n为0时结束程序
{
int num[100];
for (int i = 0; i < n; i++)
{
cin >> num[i];
}
printf("maxsubsetsum1= %d\n", maxsubsetsum1(num, n));
printf("maxsubsetsum2= %d\n", maxsubsetsum2(num, n));
printf("maxsubsetsum3= %d\n", maxsubsetsum3(num, 0, n - 1));
printf("maxsubsetsum4= %d\n", maxsubsetsum4(num, n));
}
return 0;
}
int maxsubsetsum1(int A[], int n)
{
int thissum, maxsum = A[0];//注意:maxsum的初值应当是其可能的任一值,但不可随意赋值
for (int i = 0; i < n; i++)
{
for(int j = i; j < n; j++)
{
thissum = 0;
for (int k = i; k <= j; k++)
{
thissum += A[k];
}
maxsum = maxsum >= thissum ? maxsum : thissum;
}
}
return maxsum;
}
int maxsubsetsum2(int A[], int n)
{
int thissum, maxsum = A[0];//注意:maxsum的初值应当是其可能的任一值,但不可随意赋值
for (int i = 0; i < n; i++)
{
thissum = 0;
for (int j = i; j < n; j++)
{
thissum += A[j];
maxsum = maxsum >= thissum ? maxsum : thissum;
}
}
return maxsum;
}
int maxsubsetsum3(int A[], int l, int r)
{
if (l == r) //分到最后一层,直接返回
{
return A[l];
}
int mid = (l + r) / 2; //取中间位置
int maxleftsum = maxsubsetsum3(A, l, mid); //求左组的最大子列和
int maxrightsum = maxsubsetsum3(A, mid + 1, r); //求右组的最大子列和
//该子列元素同时存在于左组和右组,即该子列中含有A[mid]和A[mid+1]
//注意:初值应当是其可能的任一值,但不可随意赋值
int maxleftmidsum = A[mid];
int leftmidsum = 0;
int maxrightmidsum = A[mid + 1];
int rightmidsum = 0;
for (int i = mid; i >= l; i--) //该子列左部分的和
{
leftmidsum += A[i];
maxleftmidsum = maxleftmidsum < leftmidsum ? leftmidsum : maxleftmidsum;
}
for (int i = mid + 1; i <= r; i++) //该子列右部分的和
{
rightmidsum += A[i];
maxrightmidsum = maxrightmidsum < rightmidsum ? rightmidsum : maxrightmidsum;
}
return max3(maxleftsum, maxrightsum , maxleftmidsum + maxrightmidsum);//左组最大子列和,右组最大子列和,包含A[mid]和A[mid+1]的最大子列和
}
int max3(int a, int b, int c) //求三者中的最大值
{
if (a < b)a = b;
if (a < c)a = c;
return a;
}
int maxsubsetsum4(int A[], int n)
{
int thissum=0, maxsum=A[0];
for (int i = 0; i < n; i++)
{
thissum += A[i];
if (thissum > maxsum)
{
maxsum = thissum;
}
else if (thissum < 0)
{
thissum = 0;
}
}
return maxsum;
}