最大子数组(最大连续区间和)问题
来源:互联网 发布:淘宝特步鞋 编辑:程序博客网 时间: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
- 最大子数组(最大连续区间和)问题
- 最大连续子数组和问题
- 连续子数组最大和问题
- 连续子数组最大和问题
- 连续子数组最大和问题
- 连续子数组最大和问题
- 连续子数组最大和问题(扫描法改进)
- 最大连续子数组问题
- 连续子数组最大和
- 连续最大子数组和
- 连续子数组最大和
- 最大连续子数组和
- 连续子数组最大和
- 最大连续子数组和
- 最大连续子数组和
- 最大连续子数组和
- 最大连续子数组和
- 最大连续子数组和
- Liunx的/proc/cpuinfo中部分信息解释
- 不需要@XmlRootElement如何使用JAXB解组javabean
- 深入理解 Session 与 Cookie
- 错误处理和调试
- Ubuntu 12.04安装java7
- 最大子数组(最大连续区间和)问题
- HVM的中断与异常处理
- IOS中的关键帧动画
- 使用Bundle在Activity之间交换数据
- Linux虚拟机设置网络、实现主机名ssh访问
- LeetCode 26: Remove Duplicates from Sorted Array
- android---(文件管理)
- 关于数组面试小题
- Apprenticeship Pattern