最大子数组问题

来源:互联网 发布:arduino摄像头编程 编辑:程序博客网 时间:2024/05/08 15:41

最大子数组问题——根据题目提供我们可以知道每一天跟前一天的变化,因此为了获得最大利益我们就要找到买入日期及出售日期。我们将每日的变化数据放入一个数组,假定low为买入后第一天,high为卖出当天。通过双重循环,我们可以用暴力方法解出它可知运行时间为Ω(n^2)显然太过麻烦。

下面就来说另一种——分治策略。

我们去找一个中间断点,假定三种情况①最大子数组在断点右侧②最大子数组在断点右侧③最大子数组包括断点。所以我们通过算出三种情况各自的最大子数组,通过比较找出其最大的子数组。通过同样的方法寻找其各自最大的子数组,所以可以通过递归实现。递归的话则需要一个触底条件,我们可以想到在一次次分割后会出现low=high那么就是只买进一天,呢最大只有其本身,向上推一层两个元素这时存在三种情况即可按上述解题思路比较得出结果向更上一层回馈结果。①②可以通过这种回馈求出,而③不行,他需要另一个函数。

//2015 by 烛龙//NEVER SAY DIE//MY LOVE BZY FOREVER#include"stdio.h"#include"limits.h"int A[1000] = {};int findmaximumcrosssubarray(int low, int mid, int high){int leftsum = INT_MIN;int rightsum = INT_MIN;int sum = 0;int maxleft, maxright;for (int i = mid; i >= low; i--){sum = sum + A[i];if (sum > leftsum){leftsum = sum;maxleft = i;}}sum = 0;for (int i = mid + 1; i <= high; i++){sum = sum + A[i];if (sum > rightsum){rightsum = sum;maxright = i;}}return (maxleft, maxright, leftsum + rightsum);}int findmaximumsubarray(int low, int high){int mid;int leftlow, lefthigh, rightlow, righthigh, crosslow, crosshigh, leftsum, rightsum, crosssum;if (low == high){return (low, high,A[low]);}else{mid = (low + high) / 2;(leftlow, lefthigh, leftsum) = findmaximumsubarray(low, mid);(rightlow, righthigh, rightsum) = findmaximumsubarray(mid + 1, high);(crosslow, crosshigh, crosssum) = findmaximumcrosssubarray(low, mid, high);if (leftsum >= rightsum&&leftsum >= crosssum){return (leftlow, lefthigh, leftsum);}else if (rightsum >= leftsum&&rightsum >= crosssum){return (rightlow, righthigh, rightsum);}else return (crosslow, crosshigh, crosssum);}}int main(){int n;scanf("%d", &n);for (int i = 1; i <= n; i++){scanf("%d", &A[i]);}int low, high;int sum;low = 1;high = n;(low,high,sum)=findmaximumsubarray(low, high);printf("%dto%dmax:%d", low, high, sum);return 0;}
这个函数就是用于实现上述思想的
int findmaximumsubarray(int low, int high){int mid;int leftlow, lefthigh, rightlow, righthigh, crosslow, crosshigh, leftsum, rightsum, crosssum;if (low == high){return (low, high,A[low]);}else{mid = (low + high) / 2;(leftlow, lefthigh, leftsum) = findmaximumsubarray(low, mid);(rightlow, righthigh, rightsum) = findmaximumsubarray(mid + 1, high);(crosslow, crosshigh, crosssum) = findmaximumcrosssubarray(low, mid, high);if (leftsum >= rightsum&&leftsum >= crosssum){return (leftlow, lefthigh, leftsum);}else if (rightsum >= leftsum&&rightsum >= crosssum){return (rightlow, righthigh, rightsum);}else return (crosslow, crosshigh, crosssum);}}

说一下计算③的想法,横跨间断点,我们可以看做i——mid+(mid+1)—— j。找出左边的一点算出左边到mid的最大值加上右边一点到mid的最大值,两者之和就是其最大值,i——j就是其横跨间断点的最大子数组。函数如下:

int findmaximumcrosssubarray(int low, int mid, int high){int leftsum = INT_MIN;int rightsum = INT_MIN;int sum = 0;int maxleft, maxright;for (int i = mid; i >= low; i--){sum = sum + A[i];if (sum > leftsum){leftsum = sum;maxleft = i;}}sum = 0;for (int i = mid + 1; i <= high; i++){sum = sum + A[i];if (sum > rightsum){rightsum = sum;maxright = i;}}return (maxleft, maxright, leftsum + rightsum);}

当然通过dp也是可以的,只不过我还不会hhhh,会了再补写。

1 0
原创粉丝点击