问题描述:
给定整数A1,A2,…,AN(可能有负值),求连续子序列和的最大值。(为方便起见,如果所有整数都为负值,则最大子序列和为0)
-
方法一:
这是个显而易见的方法,几乎每个人在第一眼看到该问题都能够想出来的方法。就是将所有的子序列找出来,然后求和最大的一个。如果序列足够大,该方法的效率可想而知。
代码如下:
#include <iostream> #include <vector> using namespace std; typedef vector<int> Vect; int maxSubSum1(const Vect &ivec, int &begin, int &end);//begin和end带回最大子序列的起点和终点 int main(void) { const int a[] = {1, 2, -5, 3, 4};
Vect ivec(a, a + sizeof(a)/sizeof(int)); int begin, end; int maxSum = maxSubSum1(ivec, begin, end); cout << maxSum << endl; if(begin == 0 && end == 0) { cout << "最大子序列和为负数。" << endl; } else { cout << "是从第" << begin << "个元素到第" << end << "个元素。" << endl; } system("pause"); return 0; } int maxSubSum1(const Vect &ivec, int &begin, int &end)//begin和end带回最大子序列的起点和终点 { int maxSum = 0;//在题目中,若做大子序列和为负数,则结果为0 begin = 0, end = 0;//若结果为负数,则begin和end都为0 for(Vect::size_type i = 0; i != ivec.size(); ++i) { int sum = 0; for(Vect::size_type j = i; j != ivec.size(); ++j) { sum += ivec.at(j);//累加得到每个子序列 if(sum > maxSum) { maxSum = sum; begin = i+1;//begin的最小值应为1 end = j+1; //end的最小值也应为1 } } } return maxSum; }
-
方法二:
采用分治的方法,将这个序列分为大小相等的两个子序列,其最大子序列和必然为:前一个子序列中的最大子序列、后一个子序列中的最大子序列和前半部分最大和(包括前半部分的最后一个元素)加上后半部分最大和(包括后半部分的第一个元素)这三者之一。
代码如下:
#include <iostream>
#include <vector>
using namespace std;
typedef vector<int> Vect;
typedef vector<int>::size_type SizeT;
int maxSubSum2(Vect &ivec, SizeT left, SizeT right);
int main(void)
{
int a[] = {1, 2, -5, 3, 4};
Vect ivec(a, a + sizeof(a)/sizeof(int));
int maxSum = maxSubSum2(ivec, 0, ivec.size()-1);
cout << maxSum << endl;
system("pause");
return 0;
}
int maxSubSum2(Vect &ivec, SizeT left, SizeT right)
{
if(left == right)//只有一个元素的情况
{
if(ivec[left] > 0)
{
return ivec[left];
}
else
{
return 0;
}
}
SizeT mid = (left + right) / 2;
int leftMaxSum = (ivec, left, mid);
int rightMaxSum = (ivec, mid+1, right);
int leftBorderMaxSum = 0, leftBorderSum = 0;
for(SizeT i = mid; i >= left; --i)
{
leftBorderSum += ivec[i];
if(leftBorderSum > leftBorderMaxSum)
{
leftBorderMaxSum = leftBorderSum;
}
/*i为unsigned int型,无论如何都不可能小于0,
*如果没有这个if语句,怎么都无法跳出循环,程
*序崩溃
*/
if(i == 0)
break;
}
int rightBorderMaxSum = 0, rightBorderSum = 0;
for(SizeT i = mid+1; i <= right; ++i)
{
rightBorderSum += ivec[i];
if(rightBorderSum > rightBorderMaxSum)
{
rightBorderMaxSum = rightBorderSum;
}
}
if(leftMaxSum > rightMaxSum)
{
return leftMaxSum > (leftBorderMaxSum + rightBorderMaxSum) ?
leftMaxSum : (leftBorderMaxSum + rightBorderMaxSum);
}
else
{
return rightMaxSum > (leftBorderMaxSum + rightBorderMaxSum) ?
rightMaxSum : (leftBorderMaxSum + rightBorderMaxSum);
}
return 0;
}
-
方法三:
采用动态规划的思想。
代码如下:
#include <iostream>
#include <vector>
using namespace std;
typedef vector<int> Vect;
typedef vector<int>::size_type SizeT;
int maxSubSum3(const Vect &ivec, int &begin, int &end);//begin和end带回最大子序列的起点和终点
int main(void)
{
int a[] = {1, -2, 2, 3, 4};
Vect ivec(a, a + sizeof(a)/sizeof(int));
int begin, end;
int maxSum = maxSubSum3(ivec, begin, end);
cout << maxSum << endl;
if(begin == 0 && end == 0)
{
cout << "最大子序列和为负数。" << endl;
}
else
{
cout << "是从第" << begin << "个元素到第" << end << "个元素。" << endl;
}
system("pause");
return 0;
}
int maxSubSum3(const Vect &ivec, int &begin, int &end)//begin和end带回最大子序列的起点和终点
{
int maxSum = 0;
int temp = 0;
begin = 0, end = 0;
for(SizeT i = 0, tag = 0; i < ivec.size(); ++i)
{
temp += ivec[i];
if(temp > maxSum)
{
maxSum = temp;
begin = tag+1;
end = i+1;
}
if(temp < 0)
{
temp = 0;
tag = i+1;
}
}
return maxSum;
}