最大子列和
一、题目描述
http://www.patest.cn/contests/mooc-ds2015spring/01-%E5%A4%8D%E6%9D%82%E5%BA%A61
给定K个整数组成的序列{ N1, N2, ..., NK },“连续子列”被定义为{ Ni, Ni+1, ..., Nj },其中 1 <= i <= j <= K。“最大子列和”则被定义为所有连续子列元素的和中最大者。例如给定序列{ -2, 11, -4, 13, -5, -2 },其连续子列{ 11, -4, 13 }有最大的和20。现要求你编写程序,计算给定整数序列的最大子列和。
输入格式:
输入第1行给出正整数 K (<= 100000);第2行给出K个整数,其间以空格分隔。
输出格式:
在一行中输出最大子列和。如果序列中所有整数皆为负数,则输出0。
输入样例:
6
-2 11 -4 13 -5 -2
输出样例:
20
二、思路解析
假设输入为-1,2,4,-6
提供了两种方法来解决最大自序列和的问题,func1是O(n^2)算法,func2是O(n)的算法。
func1中是用“组对数数”的办法,固定起点,依次向后加,即:[-1, -1+2, -1+2+4, -1+2+4-6], [2,2+4,2+4-6],[4-6],[6].....两层循环,所以是O(n^2)
func2中是考虑实际情况的算法。本算法是最大子序列求和问题,所有如果目前的自序列值thisValue已经是负的,则再往下加的话,多整体的结果起减小的作用。所以如果thisValue<0时,就抛弃目前起点开始的自序列,跳到下一个。这样只需要将数组遍历一遍,即可得到结果。
func3中是对01-复杂度2的解法,多了一个要求,即输出最大自序列中起止对应的数。
三、代码
- #include <iostream>
- #include <stdlib.h>
- using namespace std;
- const int ARRAYSIZE = 100000;
- int RESULT[3] = { 0 };
- int func1(int N, int *data);
- int func2(int N, int *data);
- void func3(int N, int *data);
- int main()
- {
- int N = 0;
- int inputData[ARRAYSIZE] = { 0 };
- int result = 0;
- int start = 0;
- int end = 0;
- //input the num of seq.
- cin >> N;
- //input each number in the seq.
- for (int i = 0; i < N; i++)
- {
- cin >> inputData[i];
- }
- //compute the sum.
- func3(N, inputData);
- //output the result
- cout << RESULT[0] << " " << RESULT[1] << " " <<RESULT[2] << endl;
- system("pause");
- return 0;
- }
- int func1(int N, int *data)
- {
- // 遍历出所有可能结果,保存最大值。复杂度为O(n^2)
- int thisValue = 0;
- int maxValue = 0;
- for (int start = 0; start < N; start++)
- {
- thisValue = data[start];
- for (int end = start + 1; end < N; end++)
- {
- // 从一个起点开始,挨个相加后面所有可能的自序列和。
- thisValue += data[end];
- if (thisValue > maxValue)
- {
- maxValue = thisValue;
- }
- }
- }
- // 根据题目maxValue>0?选择返回值。
- if (maxValue > 0)
- {
- return maxValue;
- }
- else
- {
- return 0;
- }
- }
- int func2(int N, int *data)
- {
- /* 只遍历一次,在遍历的过程中算出最大。复杂度为O(n)思路如下:
- * 1.从头开始遍历输入数据,挨个相加。thisValue表示目前子列的和,不断去更新maxValue
- * 2.在遍历过程中,以thisValue为判别条件。因为要求和的最大值,所以如果当前thisValue小于0,则舍弃此子列,thisValue重新归零。
- * 3.注意!不是说要舍弃为负数的数据,因为不知负数后面是什么。所以要以thisValue为条件。当第一个输入为负时,thisValue += data[0],也是负,自然舍弃。
- */
- int thisValue = 0;
- int maxValue = 0;
- for (int i = 0; i < N; i++)
- {
- // 定义thisValue计算方法:挨个相加
- thisValue += data[i];
- // 相加为负,对和最大无贡献,所以舍弃,即使thisValue为0
- if (thisValue < 0)
- {
- thisValue = 0;
- }
- // 当前子列和大于已有的最大,更新最大子列和
- if (thisValue > maxValue)
- {
- maxValue = thisValue;
- }
- }
- // 根据题目要求返回相应数值。>0返回最大子列值,<0返回0.
- if (maxValue > 0)
- {
- return maxValue;
- }
- else
- {
- return 0;
- }
- }
- void func3(int N, int *data)
- {
- /* 也是最大子列和问题,但输出有变化。首先要输出最大子列和,其次要输出是最大子列和相对应子列的起止元素。
- 思路:用func2中的O(n)算法,加一个计数器
- */
- int thisValue = 0;
- int maxValue = 0;
- int start = 0;
- int count = 0;
- int end = 0;
- for (int i = 0; i < N; i++)
- {
- thisValue += data[i];
- if (thisValue <= 0)
- {
- count = 0;
- thisValue = 0;
- }
- else
- {
- count += 1;
- if (thisValue > maxValue)
- {
- maxValue = thisValue;
- end = i;
- start = i - count + 1;
- }
- }
- // cout << "i:" << i << " start:" << start << " thisValue:" << thisValue << " end" << end << endl;
- }
- if (maxValue > 0)
- {
- RESULT[0] = maxValue;
- RESULT[1] = data[start];
- RESULT[2] = data[end];
- }
- else
- {
- RESULT[0] = 0;
- RESULT[1] = data[0];
- RESULT[2] = data[N - 1];
- }
- }