最大子数组(最大连续区间和)问题

来源:互联网 发布:淘宝特步鞋 编辑:程序博客网 时间:2024/06/04 18:14

1,应用背景:

最大子数组的问题可以用到股票市场,比如想得知在一段时间内怎么让股票买进卖出后的利益最大。就可以转化为最大子数组问题。

2,解决方法:

(1)暴力枚举法,O(n3)

#include "stdafx.h"#include <Windows.h>#include <ctime>#include<iostream>using namespace std;//暴力枚举法,O(n^3)#define AFFINITY -65536void Max_Subarray_0(int *a, int length){int i,j,k;int left_num = 0,right_num = length -1,max_sum = AFFINITY,sum;for (i = 0; i < length; i++){for (j = i; j < length; j++){sum = 0;for (k = i; k <= j; k++){sum = sum + a[k]; if (sum > max_sum){max_sum = sum;left_num = i;right_num = j;}}}}cout << "最大子数组下标为:" << left_num << "-------" << right_num << endl;cout << "最大子数组和为:" << max_sum << endl;}
(2)同样是枚举法,但是利用了前边一次计算的结果,O(n2)

//利用前边计算的结果,O(n2)void Max_Subarray_1(int *a, int length){int i,j;int left_num = 0,right_num = length - 1,sum, max_sum = AFFINITY;for (i = 0; i < length; i++){sum = 0;for (j = i; j < length; j++){sum = sum + a[j];if (sum > max_sum){max_sum = sum;left_num = i;right_num = j;}}}cout << "最大子数组下标为:" << left_num << "-------" << right_num << endl;cout << "最大子数组和为:" << max_sum << endl;}
(3)分治法;O(nlogn)

//分治法,主要思想是,子数组要么在[low,mid]中,要么在[mid+1,high]中,要么横跨mid;
//O(nlogn)
//这是求横跨mid时的最大子数组

int* Find_Max_Cross_Subarray(int *a, int low, int mid, int high){int i,j;int left_num = 0,righ_num = high,left_max_sum = AFFINITY,right_max_sum = AFFINITY,sum = 0;for (i = mid; i >= low; i--){sum = sum + a[i];if (sum > left_max_sum){left_max_sum = sum;left_num = i;}}sum = 0;for (j = mid; j <= high; j++){sum = sum + a[j];if (sum > right_max_sum){right_max_sum = sum;righ_num = j;}}int max_cross_sum = left_max_sum + right_max_sum - a[mid];    //int b[3]= {left_num, righ_num, max_cross_sum};//return b;这样返回是不正确的,因为b是在栈中申请的空间,函数结束后就释放了,该成这样int *b = new int[3];b[0] = left_num;b[1] = righ_num;b[2] = max_cross_sum;return b;//因为b是在堆里申请的空间,不会立即释放,需要delete}//下边就是分治算法代码了int* Find_Max_Subarray_3(int *A, int low, int high){int *a;if (low == high){int R[3];R[0] = low;R[1] = high;R[2] = A[low];return R;//这里可以这么返回,因为R的空间虽是在栈中,但整个递归结束后才释放,//所以是可以用来在递归中作为返回值传递的}else{int R1[3];int R2[3];int R3[3];int mid = (low + high)/2;a = Find_Max_Subarray_3(A, low, mid);//a所指空间是在该函数中申请的,现在该函数结束了,//空间要回收了,故执行完赋值语句后,再执行cout语句,输出的a值不同于赋值前的值了R1[0] = a[0];R1[1] = a[1];R1[2] = a[2];//cout << R1[0] << ' ' << R1[1] << ' ' << R1[2] << endl;//cout << a[0] << ' ' << a[1] << ' ' << a[2] << endl;//cout << a[0] << ' ' << a[1] << ' ' << a[2] << endl;a = Find_Max_Subarray_3(A, mid+1, high);R2[0] = a[0];R2[1] = a[1];R2[2] = a[2];//cout << R2[0] << ' ' << R2[1] << ' ' << R2[2] << endl;a = Find_Max_Cross_Subarray(A, low, mid, high);R3[0] = a[0];R3[1] = a[1];R3[2] = a[2];//cout << R3[0] << ' ' << R3[1] << ' ' << R3[2] << endl;if (R1[2] >= R2[2] && R1[2] >= R3[2]){return R1;}elseif (R2[2] >= R1[2] && R2[2] >= R3[2]){return R2;}else{return R3;}}}

接收返回值时要注意,因为返回的是栈空间。具体描述在主函数中有。

(4)统计学家发明的一个O(n)方法,这个方法主要利用的是求a[i]的最大后缀和max_suf_sum。

//还有一个统计学家发明的算法,O(n)int *Find_Max_Subarray_4(int *a, int length){int left_low, right_high;int max_suf_sum = AFFINITY;int max_sum = AFFINITY;for (int i = 0; i < length; i++){max_suf_sum = max_suf_sum + a[i];if (max_suf_sum <= a[i]){max_suf_sum = a[i];left_low = i;}if (max_sum <= max_suf_sum){max_sum = max_suf_sum;right_high = i;}}int *b = new int[3];b[0] = left_low;b[1] = right_high;b[2] = max_sum;return b;}
(5)下边是主函数

int _tmain(int argc, _TCHAR* argv[]){//int a[] = {13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7};//这个数组的输出为(7,10,43);//Max_Subarray_0(a, 16);//Max_Subarray_1(a, 16);//int *M = Find_Max_Cross_Subarray(a,7,0,15);//int a[] = {13, -3, -25, 20, -3};  cout << "输入数组的规模!"<< endl;  int num;  cin >> num;  int *a = new int[num];  cout << "建立随机数组!"<< endl;  srand((int)time(0));  for (int i = 0; i < num; i++)  {  a[i] = rand()%2001 - 1000;  //cout << a[i] << endl;  }  double start = GetTickCount();//int* M = Find_Max_Subarray_3(a,0,num - 1);int* M = Find_Max_Subarray_4(a,num);//for (int i = 0; i < 3; i++)//因为Find_Max_Subarray_3返回的是栈空间//{// cout << M[i] << endl;//执行cout会改变返回栈空间的值,这样输出结果不对//}//改成这样double end = GetTickCount();int Result[3];//注意接收函数返回值时先全部赋值,再coutfor (int i = 0; i < 3; i++){Result[i] = M[i];//cout << 5;//这里用cout函数也不行,同样改变了栈空间的值}cout << "运行时间为:" << end - start << "毫秒!" << endl;cout << "下标 上标 最大值" << endl;cout << Result[0] << ' ' << Result[1] << ' ' << Result[2] << endl;delete []a;system("pause");return 0;}
关于函数返回指针的一些问题,在下边链接中可以看到!

http://blog.csdn.net/zzuchengming/article/details/49339605

测试1000万随机数,O(n)算法的时间为46毫秒!

分治算法O(nlogn)的时间为10967毫秒!

1 0