求整数数组中和最大的子数组的3种方法

来源:互联网 发布:中兴和华为知乎 编辑:程序博客网 时间:2024/06/06 12:58

输入一个整型数组,数组里有正数也有负数。数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。求所有子数组的和的最大值。要求时间复杂度为O(n)。

使用三种方式实现,分别是蛮力法:bf_MaxSubArray,分治法:dc_MaxArray,和O(n)实现的单循环法find_max。

#include"stdio.h"#include"math.h"#include"time.h"#include"windows.h"#define MIN_INT -10000#define MAX_INT 10000typedef struct{int max_left;int max_right;int max;}maxinfo;maxinfo bf_MaxSubArray(int *a,int n){maxinfo max;max.max_left= 0;max.max_right= 0;max.max= MIN_INT;int tmp=0;for(int i=0;i<n;i++){for(int j=i;j<n;j++){tmp += a[j];if(tmp > max.max){max.max = tmp;max.max_left = i;max.max_right = j;}}tmp = 0;}return max;}maxinfo dc_FindMaxCrossingSubArray(int *a,int left,int mid,int right){maxinfo leftMax;leftMax.max_left= mid;leftMax.max_right = mid;leftMax.max= MIN_INT;int tmp = 0;for(int i=mid;i>=left;i--){tmp += a[i];if(tmp>leftMax.max){leftMax.max = tmp;leftMax.max_left = i;}}maxinfo rightMax;rightMax.max_left=mid+1;rightMax.max_right = mid+1;rightMax.max= MIN_INT;tmp = 0;for(int j = mid+1;j<right+1;j++){tmp += a[j];if(tmp>rightMax.max){rightMax.max = tmp;rightMax.max_right = j;}}leftMax.max += rightMax.max;leftMax.max_right = rightMax.max_right;return leftMax;}maxinfo dc_MaxArray(int *a,int left,int right){if(left==right){maxinfo sgele;sgele.max_left=left;sgele.max_right = right;sgele.max= a[left];return sgele;}else{int mid = (int)floor((left+right)/2);maxinfo tmp;maxinfo maxleft = dc_MaxArray(a,left,mid);maxinfo maxright = dc_MaxArray(a,mid+1,right);maxinfo maxcross = dc_FindMaxCrossingSubArray(a,left,mid,right);tmp = maxleft.max>maxright.max?maxleft:maxright;tmp = tmp.max>maxcross.max?tmp:maxcross;return tmp;}}void show(maxinfo max){printf("收益最大的是:%d号前买入,%d号后卖出,收益$%d/股.\n",max.max_left+1,max.max_right+1,max.max);}void find_max(int *ary,int ARYSIZE){int max=0;//保存最大和int curSum=0;//保存当前和int curStart=0;//当前和的起始位置int start=0;//最大和的起始位置int end=0;//最大和的终止位置for(int i=0;i<ARYSIZE;i++){if(i==0){curSum=max=ary[i];continue;}if(curSum<0){curSum=0;//与负数相加,和会减小,所以抛弃以前的和curStart=i;}//最大值已经被保存下来,所以请大胆的继续往前加curSum += ary[i];//当前和被保存为最大值,记录下它的起始位置和结束位置if(curSum>max){max=curSum;start=curStart;end=i;}}printf("和最大的子数组为:\n");for(int j=start;j<=end;j++){printf("%d ",ary[j]);}printf("= %d",max);}void main(){int n = 16;int a[] = {13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7};//{-13,-3,-25,-20,-3,-16,-23,-18,-20,-7,-12,-5,-22,-15,-4,-7};//int i=clock();show(bf_MaxSubArray(a,n));printf("\n==============\n");find_max(a,n);printf("\n==============\n");printf("计算耗时:%dms\n",clock()-i);int mid = (int)floor((n-1)/2);show(dc_FindMaxCrossingSubArray(a,0,mid,n-1));maxinfo result;LARGE_INTEGER nFreq;LARGE_INTEGER nBeginTime;LARGE_INTEGER nEndTime;double time;QueryPerformanceFrequency(&nFreq);QueryPerformanceCounter(&nBeginTime); //开始result = bf_MaxSubArray(a,n);//dc_MaxArray(a,0,n-1);QueryPerformanceCounter(&nEndTime);time=(double)(nEndTime.QuadPart-nBeginTime.QuadPart)/(double)nFreq.QuadPart;printf("%f微妙\n",time);show(result);printf("\n");  }


其中最优方法的参考地址:求整数数组中和最大的子数组

原创粉丝点击