求连续子数组的最大和:这里我就把我自己理解的动态规划算法按照自己的理解写一下
动态规划:
分析:
已知:数组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的初始值赋值!
其实这个连续子数组是有多个的,以上解法只是求一个最优解!我目前还没想好如何求所有的解(连续子数组)