求连续子数组的最大和:这里我就把我自己理解的动态规划算法按照自己的理解写一下
动态规划:
分析:
已知:数组arry[1~n]
问题:如果现在我们已经知道了arry[1~i-1](i>1)中连续子数组的最大和,那么如果扩展到arry[1~i]数组中连续子数组的最大和呢?
求解:假设现在我们已经知道了这个最大的连续子数组,那么这个连续的子数组要么包含arry[i]元素,要么不包含arry[i]这个元素
1)如果包含arry[i]元素,那就是以arry[i]结尾的连续子数组的和;
2)如果不包含arry[i]这个元素,那么就是arry[1~i-1]中连续子数组的最大和;
记maxEndingHere[i]:以arry[i]结尾的连续子数组的和;
记maxSofar[i]:arry[1~i]数组中最大的连续子数组和;
故递推表达式:maxSofar[i] = max(maxSofar[i-1], maxEndingHere[i]);
问题一:输入一个整型数组,数组里有正数也有负数。数组中一个或连续的多个整数组成一个子数组,求子数组的和的最大值
如果数组中都是负数时,最大总和子向量是绝对值最小的那个负数;
#include <iostream>
using namespace std;
/*
题目:输入一个整型数组,数组里有正数也有负数。
数组中一个或连续的多个整数组成一个子数组。
求子数组的和的最大值。
*/
const int MINVALUE = -1000;
//数组arry的0位置处不存有任何数
void longSubArry(int arry[], int n)
{
int maxEndingHere = MINVALUE;
int maxSofar = MINVALUE;
int maxEndingHereBeginIndex = 0;
int maxEndingHereEndIndex = 0;
int maxSofarBeginIndex = 0;
int maxSofarEndIndex = 0;
for (int i = 1; i<=n; i++)
{
//maxEndingHere表示以arry[i-1]结尾的连续子数组的最大和,求以arry[i]结尾的连续子数组的最大和
if (maxEndingHere<=0)
{
maxEndingHere = arry[i];
maxEndingHereBeginIndex = i;
maxEndingHereEndIndex = i;
}
else
{
maxEndingHere = maxEndingHere + arry[i];
maxEndingHereEndIndex = i;
}
if (maxEndingHere >= maxSofar) //将以arry[i]结尾的连续子数组的最大和 与 arry[1~i]数组中最大连续子数组的和进行刚比较
{
maxSofar = maxEndingHere;
maxSofarBeginIndex = maxEndingHereBeginIndex;
maxSofarEndIndex = maxEndingHereEndIndex;
}
}
cout<<"连续子数组最大的和为:"<<maxSofar<<",开始位置为:"<<maxSofarBeginIndex<<",结束位置为:"<<maxSofarEndIndex<<endl;
}
int main()
{
int arry[] = {0, 1, -2, 3, 10, -4, 7, 2, -5};
longSubArry(arry, 8);
int arryB[] = {0, -1, -2, -3, -10, -4, -7, -2, -5};
longSubArry(arryB, 8);
int arryC[] = {0, 1, 2, 3, 10, 4, 7, 2, 5};
longSubArry(arryC, 8);
system("pause");
return 0;
}
问题二:输入一个整型数组,数组里有正数也有负数。数组中一个或连续的多个整数组成一个子数组,求子数组的和的最大值
如果数组中都是负数时,最大总和子向量为空,和为0;(有了这个区别,连续子数组的和的最小为0)
void longSubArrySecond(int arry[], int n)
{
int maxEndingHere = 0;
int maxSofar = 0;
int maxEndingHereBeginIndex = 0; //表示子数组中不包含任何元素
int maxEndingHereEndIndex = 0;
int maxSofarBeginIndex = 0;
int maxSofarEndIndex = 0;
for (int i = 1; i<=n; i++)
{
//以arry[i-1]结尾的连续子数组的最大和要么是正数要么是0
//现在要求以arry[i]结尾的连续子数组的最大和
//因为要记录开始索引和结束索引,写的就比较麻烦
/*if(maxEndingHere > 0 && (maxEndingHere + arry[i]) >0)
{
maxEndingHere = maxEndingHere + arry[i];
maxEndingHereEndIndex = i;
}
else if(maxEndingHere > 0 && (maxEndingHere + arry[i])<=0)
{
maxEndingHere = 0;
maxEndingHereBeginIndex = 0;
maxEndingHereEndIndex = 0;
}
else if (maxEndingHere == 0 && arry[i]>0)
{
maxEndingHere = arry[i];
maxEndingHereBeginIndex = i; //this is very important
maxEndingHereEndIndex = i;
}
else if(maxEndingHere == 0 && arry[i] <=0)
{
maxEndingHere = 0;
maxEndingHereBeginIndex = 0;
maxEndingHereEndIndex = 0;
}*/以上这些代码写的有些麻烦,可改进
//计算maxEndingHere[i]
if (maxEndingHere <= 0)//注意要包含0
{
maxEndingHere = arry[i];
maxEndingHereBeginIndex = i;
maxEndingHereEndIndex = i;
}
else
{
maxEndingHere = maxEndingHere + arry[i];
maxEndingHereEndIndex = i;
}
//计算maxSofar[i]
if (maxSofar <= maxEndingHere)
{
maxSofar = maxEndingHere;
maxSofarBeginIndex = maxEndingHereBeginIndex;
maxSofarEndIndex = maxEndingHereEndIndex;
}
}
cout<<"连续子数组最大的和(全为负数即为0)为:"<<maxSofar<<",开始位置为:"<<maxSofarBeginIndex<<",结束位置为:"<<maxSofarEndIndex<<endl;
}
在写这些函数的时候,我的错误就出在:
根据 以aryy[i-1]结尾的连续子数组的最大和 来求 以arry[i]结尾的连续子数组的最大值;不同题目的需求导致我们代码考虑就不一样~~~~~~其实粗略看,两者的代码是相同的。不同的地方就在于maxEndingHere和maxSofar的初始值赋值!
其实这个连续子数组是有多个的,以上解法只是求一个最优解!我目前还没想好如何求所有的解(连续子数组)