给定K个整数组成的序列{ N1, N2 , …, NK },“连续子列”被定义为{ Ni , Ni+1 , …, Nj
},其中 1≤i≤j≤K。“最大子列和”则被定义为所有连续子列元素的和中最大者。例如给定序列{ -2, 11, -4, 13, -5, -2 },其连续子列{ 11, -4, 13 }有最大的和20。现要求你编写程序,计算给定整数序列的最大子列和。
本题旨在测试各种不同的算法在各种数据情况下的表现。各组测试数据特点如下:
数据1:与样例等价,测试基本正确性;
数据2:102个随机整数;
数据3:103个随机整数;
数据4:104个随机整数;
数据5:105个随机整数;
输入格式:
输入第1行给出正整数K (≤100000);第2行给出K个整数,其间以空格分隔。
输出格式:
在一行中输出最大子列和。如果序列中所有整数皆为负数,则输出0。
输入样例:
6
-2 11 -4 13 -5 -2
输出样例:
20
本题第一思路为暴力法,即计算所有子列的和,并从中选取最大的值
#include
#define maxsize 100002 //定义最大数组
int main ( ) {
int i, j, ThisSum = 0, MaxSum = 0;
int n, flag = 0; //flag作为全负输入的标志
int num[maxsize];
scanf ("%d", &n);
for ( i = 0; i < n; i++) {
scanf ("%d", &num[i]);
}
//每次从i开始,依次往后取各个子列和
for ( i = 0; i < n; i++) {
ThisSum = 0; //每次求新的子列和时将初始结果置为0
for (j = i; j < n; j++) {
ThisSum = ThisSum + num[j];
if ( num[j] > 0) flag = 1;
if (ThisSum > MaxSum) {
MaxSum = ThisSum;
}
}
}
if (flag) printf ("%d\n", MaxSum);
else printf ("0\n");
return 0;
}
显然,暴力法求解的时间复杂度为O(n²),为提高算法的效率,考虑使用在线算法;
在线算法的原理:从第一个数开始逐个往后累加,当此时计算的和为负数时,说明前一部分子列已经无法对后续子列和的增加提供作用,因此可以将前部分和变为0;同时,在每次计算时,将当前计算的和与最大和进行比较,若大于最大和则进行赋值;
#include
int main () {
int n = 0, maxsum = 0, sum = 0, i, num;
scanf ("%d", &n);
for (i = 0; i < n; i++) {
scanf ("%d", &num);
sum = sum + num;
if (sum < 0) sum = 0;
if (maxsum < sum ) maxsum = sum;
}
printf ("%d",maxsum);
return 0;
}
该算法时间复杂度为O(n),pta评判结果
Given a sequence of K integers{ N1, N2 , …, NK }. A continuous subsequence is defined to be{ Ni , Ni+1 , …, Nj}, where 1≤i≤j≤K. The Maximum Subsequence is the continuous subsequence which has the largest sum of its elements. For example, given sequence { -2, 11, -4, 13, -5, -2 }, its maximum subsequence is { 11, -4, 13 } with the largest sum being 20.
Now you are supposed to find the largest sum, together with the first and the last numbers of the maximum subsequence.
Input Specification:
Each input file contains one test case. Each case occupies two lines. The first line contains a positive integer K (≤10000). The second line contains K numbers, separated by a space.
Output Specification:
For each test case, output in one line the largest sum, together with the first and the last numbers of the maximum subsequence. The numbers must be separated by one space, but there must be no extra space at the end of a line. In case that the maximum subsequence is not unique, output the one with the smallest indices i and j (as shown by the sample case). If all the K numbers are negative, then its maximum sum is defined to be 0, and you are supposed to output the first and the last numbers of the whole sequence.
Sample Input:
10
-10 1 2 3 4 -5 -23 3 7 -21
Sample Output:
10 1 4
第二题相比较与第一题在算法原理上是一致的,只增加了需要额外输出最大子列和的最小组合的上下界,因此,在第一题在线算法的基础上调整:
/*在线法计算最大子列和*/
#include
#define maxsize 100002
int main () {
int n, MaxSum = 0, ThisSum = 0, i,flag = 0; //flag用于确定输入的数中是否全为负数
int min_left=0, min_right=0,left=0;
int num[maxsize];
scanf ("%d", &n);
for (i = 0; i < n; i++) {
scanf ("%d", &num[i]);
ThisSum = ThisSum + num[i];
if (ThisSum < 0) {
ThisSum = 0;
left = i + 1; //当将前部分子列全部去除后,将左标识符移动到后一位,并保留此时的标识符
}
if (MaxSum < ThisSum ) {
MaxSum = ThisSum;
min_right = i;
min_left = left; //由于此时当前计算值已经大于最大值,将左侧的标识符置为当前纳入计算的子列的左侧标识符,并开始保存右侧标识符
}
if (num[i] > 0) flag = 1;
if (num[i] == 0 && flag == 0) {
//由于在移动上下界时,判断条件为ThisSum<0以及MaxSum
min_left = min_right = i;
}
}
if (flag == 0) {
if (num[min_left]==0) {
printf ("%d %d %d",MaxSum, num[min_left], num[min_right]);
} else {
MaxSum = 0;
printf ("%d %d %d",MaxSum, num[0], num[n-1]);
}
}
else printf ("%d %d %d",MaxSum, num[min_left], num[min_right]);
return 0;
}
在最开始提交的时候,一直出现的错误在第5步,没有考虑到移动左右标识符的问题,会导致即使有0的条件下,仍然按照全部为负的状态进行输出,与题意不符。