您的位置:首页 > 其它

最大子列和

2016-01-24 10:21 531 查看
一、题目描述
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的解法,多了一个要求,即输出最大自序列中起止对应的数。

三、代码

[cpp] view plain copy

#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];

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: