最大序列和问题

来源:互联网 发布:mac 命令行卸载软件 编辑:程序博客网 时间:2024/06/05 02:19
最大子序列和的问题:就是给出一组数据,求出里面那几个前后连续的数的和最大。
书中给出4个算法,时间复杂度从O(N^3)降到O(N^2)再降到O(NlogN)最后到O(N),这就是人家跑完程序都走上人生巅峰了,你面对一组数据苍颜白发却还在等待结果...

//O(N^3)int maxSubSum1(const vector & a){int maxSum = 0;for (int i = 0; i < a.size(); ++i)for (int j = i; j < a.size(); ++j){int thisSum = 0;//这个for其实就是多余写出来...for (int k = i; k <= j; ++k)thisSum += a[k];if (thisSum > maxSum)maxSum = thisSum;}return maxSum;}//O(N^2) 优化的就是上一个算法里的forint maxSubSum2(const vector & a){int maxSum = 0;for (int i = 0; i < a.size(); ++i){int thisSum = 0;for (int j = i; j < a.size(); ++j) {thisSum += a[j];if (thisSum > maxSum)maxSum = thisSum;}}return maxSum;}//分治法O(NlogN)int maxSumRec(const vector &a, int left, int right){if (left == right)//只有一个元素if (a[left] > 0)return a[left];elsereturn 0;int center = (left + right) / 2;int maxLeftSum = maxSumRec(a, left, center);int maxRightSum = maxSumRec(a, center + 1, right);int maxLeftBorderSum = 0, leftBorderSum = 0;for (int i = center; i >= left; --i){leftBorderSum += a[i];if (leftBorderSum > maxLeftBorderSum)maxLeftBorderSum = leftBorderSum;}int maxRightBorderSum = 0, rightBorderSum = 0;for (int j = center + 1; j <= right; ++j){rightBorderSum += a[j];if (rightBorderSum > maxRightBorderSum)maxRightBorderSum = rightBorderSum;}int maxSum1 = maxLeftSum > maxRightSum ? maxLeftSum : maxRightSum;return max(maxSum1, maxLeftBorderSum + maxRightBorderSum);}int maxSubSum3(const vector &a){return maxSumRec(a, 0, a.size() - 1);}//O(N)逆天了int maxSubSum4(const vector &a){//任何负值不可能是最大子序列的开头int maxSum = 0, thisSum = 0;for (int i = 0; i < a.size(); ++i){thisSum += a[i];if (thisSum > maxSum)maxSum = thisSum;else if (thisSum < 0)thisSum = 0;}return maxSum;}int main(){vector a = { 4,-3,5,-2,-1,2,6,-2 };cout << maxSubSum1(a) << endl;cout << maxSubSum2(a) << endl;cout << maxSubSum3(a) << endl;cout << maxSubSum4(a) << endl;system("pause");

算法4是许多聪明算法的典型,它只对数据进行一次扫描,一旦a[i]被读入并被处理,就不再需要被记忆。在任意时刻,算法都能对它已经读入的数据给出子序列问题的正确答案。(联机算法(on-line algorithm),ps:仅需要常量空间并以线性时间与线性时间运行的算法几乎是完美的算法,我不造哦~)

有了最大子序列和的问题就有了最小子序列和, 照葫芦画瓢,好的算法你不用,我也很绝望啊~

int minSubSum4(const vector &a){int minSum = 0, thisSum = 0;for (int i = 0; i < a.size(); ++i){thisSum += a[i];if (thisSum < minSum)minSum = thisSum;else if (thisSum > 0)thisSum = 0;}return minSum;}

然后是最小正子序列和:
我成为我渣了,只想到了O(N^2)...

int main(){vector a = { 4,-3,5,-2,-1,2,6,-2 };//如下为算法int minSum = a[0];for (int i = 0; i != a.size(); ++i) {int thisSum = 0;for (int j = i; j != a.size(); ++j) {thisSum += a[j];if (minSum > thisSum && thisSum > 0)minSum = thisSum;}}cout << minSum;system("pause");}


然后学会了这个O(NlogN): 耗时的是里面的排序,因为它是O(NlogN)
具体是 对累计的和排序,然后对应出索引,找出可以成为序列的索引即可,注意对于相同的大小数据索引要一致

struct item {int index;int value;};bool cmp(item &a, item &b){//相同的值,让其索引为小的,否则就不是之比较相邻两个数的索引那么简单了if (a.value == b.value)a.index = b.index = a.index < b.index ? a.index : b.index;return a.value < b.value;}void minPSubSum(const vector &a){vector b;item temp;int thisSum = 0;//所选序列为(x,y]temp.index = 0;temp.value = 0;b.push_back(temp);for (size_t i = 0; i < a.size(); ++i){thisSum += a[i];temp.value = thisSum;temp.index = i+1;b.push_back(temp);}sort(b.begin(), b.end(), cmp);int minPSum = b.rbegin()->value;for (size_t j = 0; j < b.size() - 1; ++j){if (b[j].index < b[j + 1].index){thisSum = b[j + 1].value - b[j].value;if (thisSum < minPSum)minPSum = thisSum;}}cout << minPSum< a = { 4,-3,5,-2,-1,2,6,-2 };vector b = { 4,  0, 4,  1,  -1 };minPSubSum(a);minPSubSum(b);system("pause");}


最大子序列乘积:

这个是没想出来,但是看到了这个公式,就秒懂了,瞬间感触也很多,对自己渣,对别人的强,以及那么多时间的停滞不前
i=1  --->>size()-1
max(a[i], maxArray[i - 1] * a[i], minArray[i - 1] * a[i]);
min (a[i], maxArray[i - 1] * a[i], minArray[i - 1] * a[i]);

int max(int a, int b, int c){int max = a;if (b > max)max = b;if (c > max)max = c;return max;}int min(int a, int b, int c){int min = a;if (b < min)min = b;if (c < min)min = c;return min;}void maxPlus(const vector &a){int maxValue= a[0];vector maxArray;maxArray.push_back(maxValue);vector minArray{ maxArray };for (size_t i = 1; i < a.size(); ++i){    //算法的精髓maxArray.push_back(max(a[i], maxArray[i - 1] * a[i], minArray[i - 1] * a[i]));minArray.push_back(min(a[i], maxArray[i - 1] * a[i], minArray[i - 1] * a[i]));if (maxArray.back() > maxValue)maxValue = maxArray.back();} cout << maxValue << endl;}int main(){vector a = { 4,-3,5,-2,-1,2,6,-2 };vector b = { 4,  0, 4,  1,  -1 };maxPlus(a);maxPlus(b);system("pause");}


to be continue!!!



原创粉丝点击