最大子序列和的四种求解算法及其时间比较
2015-07-26 15:02
465 查看
1、T(N)=O(N^3)
2、T(N)=O(N^2)
3、T(N)=O(NlogN),底数为2
PS:用分治法,先将原序列分成相似的两个子序列,这样可以得出一个结论,
那就是最大子序列和要不在左子序列中,要不在右子序列中,要不在左子序列和右子序列的连接处
对左子序列递归求最大序列和,对右子序列求最大序列和,再将左右子序列连接起来,求连接处的最大序列和
最后比较就能求出整体最大序列和
4、T(N)=O(N)
推荐用这种算法
5、数量级及其时间比较表格
6、源代码及其测试数据
__int64 algorithm1(__int64 a[],__int64 n) //T(N)=O(N^3) { __int64 MaxSum = 0; __int64 ThisSum; for(__int64 i = 0; i < n; i++) //i从零开始到最后一个数字 { for(__int64 j = i; j < n; j++) //j从i开始到最后一个数字 { ThisSum = 0; //PS:第一轮循环k从0->0,0->1,0->2...0->n //PS:第二轮循环k从1->1,1->2,1->3...1->n //PS:第K轮循环k从k->k,k->k+1,k->k+2...k->n //PS:这样就遍历完序列中所有子序列的可能性 for(__int64 k = i; k <= j; k++) //从i开始到j的数字相加 ThisSum += a[k]; if(ThisSum > MaxSum) //大于最大子序列之和则替换 MaxSum = ThisSum; } } return MaxSum; }
2、T(N)=O(N^2)
__int64 algorithm2(__int64 a[],__int64 n) //T(N)=O(N^2) { __int64 MaxSum = 0; __int64 ThisSum; for(__int64 i = 0; i < n; i++) //i从零开始到最后一个数字 { ThisSum = 0; //PS:第一轮j从0->n,每循环一次,判断一次 //PS:第二轮j从1->n,每循环一次,判断一次 //PS:第J轮j从j->n,每循环一次,判断一次 //PS:这样就遍历完序列中所有子序列的可能性 for(__int64 j = i; j < n; j++) //j从i开始到最后一个数字 { ThisSum += a[j]; if(ThisSum > MaxSum) //大于最大子序列之和则替换 MaxSum = ThisSum; } } return MaxSum; }
3、T(N)=O(NlogN),底数为2
PS:用分治法,先将原序列分成相似的两个子序列,这样可以得出一个结论,
那就是最大子序列和要不在左子序列中,要不在右子序列中,要不在左子序列和右子序列的连接处
对左子序列递归求最大序列和,对右子序列求最大序列和,再将左右子序列连接起来,求连接处的最大序列和
最后比较就能求出整体最大序列和
__int64 MaxSubSum(__int64 a[],__int64 Left,__int64 Right) { __int64 Center; //中间元素 __int64 MaxLeftSum,MaxRightSum; //左右子序列最大序列和 __int64 MaxLeftBorderSum,MaxRightBorderSum; //左右边界最大序列和 __int64 LeftBorderSum,RightBorderSum; //左右边界序列和 if(Left == Right) //递归出口 if(a[Left] > 0) //当a[i]>0时,返回该元素 return a[Left]; else //否则返回0 return 0; Center = (Left + Right) / 2; MaxLeftSum = MaxSubSum(a,Left,Center); //递归求解左子序列 MaxRightSum = MaxSubSum(a,Center + 1,Right); //递归求解右子序列 MaxLeftBorderSum = 0; LeftBorderSum = 0; for(__int64 i = Center; i>= Left; i--) //求左边界最大序列和 { LeftBorderSum += a[i]; if(LeftBorderSum > MaxLeftBorderSum) MaxLeftBorderSum = LeftBorderSum; } MaxRightBorderSum = 0; RightBorderSum = 0; for(__int64 i = Center + 1; i <= Right; i++) //求右边界最大序列和 { RightBorderSum += a[i]; if(RightBorderSum > MaxRightBorderSum) MaxRightBorderSum = RightBorderSum; } return max(max(MaxLeftSum,MaxRightSum),MaxLeftBorderSum+MaxRightBorderSum); //返回整体最大序列和 } __int64 algorithm3(__int64 a[],__int64 n) //T(N)=O(NlogN),底数为2 { return MaxSubSum(a,0,n - 1); }
4、T(N)=O(N)
推荐用这种算法
__int64 algorithm4(__int64 a[],__int64 n) //T(N)=O(N) { __int64 ThisSum = 0; __int64 MaxSum = 0; for(int i = 0; i < n; i++) //i从零开始到最后一个数字 { ThisSum += a[i]; if(ThisSum < 0) //当a[j]+...+a[i] < 0,则舍弃i之前的所有序列,从i后继续累加 ThisSum = 0; if(ThisSum > MaxSum) //求出当前序列的最大子序列和 MaxSum = ThisSum; } return MaxSum; }
5、数量级及其时间比较表格
Algorithm | 1 | 2 | 3 | 4 | |||||
Time | O(N^3) | T/N Rate | O(N^2) | T/N Rate | O(NlogN) | T/N Rate | O(N) | T/N Rate | |
Input Size(N) | 10 | 0.903 | 0.0903 | 0.771 | 0.0771 | 0.734 | 0.0734 | 0.707 | 0.0707 |
100 | 1.069 | 0.01069 | 0.791 | 0.00791 | 0.784 | 0.00784 | 0.744 | 0.00744 | |
1000 | 3.538 | 0.003538 | 0.952 | 0.000952 | 0.805 | 0.000805 | 0.78 | 0.00078 | |
10000 | 3000 | 0.3 | 1.599 | 0.0001599 | 1.067 | 0.0001067 | 0.859 | 0.0000859 | |
100000 | 3000000 | 30 | 73.844 | 0.00073844 | 1.255 | 0.00001255 | 1.125 | 0.00001125 |
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <ctime>
using namespace std;
__int64 algorithm1(__int64 a[],__int64 n) //T(N)=O(N^3) { __int64 MaxSum = 0; __int64 ThisSum; for(__int64 i = 0; i < n; i++) //i从零开始到最后一个数字 { for(__int64 j = i; j < n; j++) //j从i开始到最后一个数字 { ThisSum = 0; //PS:第一轮循环k从0->0,0->1,0->2...0->n //PS:第二轮循环k从1->1,1->2,1->3...1->n //PS:第K轮循环k从k->k,k->k+1,k->k+2...k->n //PS:这样就遍历完序列中所有子序列的可能性 for(__int64 k = i; k <= j; k++) //从i开始到j的数字相加 ThisSum += a[k]; if(ThisSum > MaxSum) //大于最大子序列之和则替换 MaxSum = ThisSum; } } return MaxSum; }
__int64 algorithm2(__int64 a[],__int64 n) //T(N)=O(N^2) { __int64 MaxSum = 0; __int64 ThisSum; for(__int64 i = 0; i < n; i++) //i从零开始到最后一个数字 { ThisSum = 0; //PS:第一轮j从0->n,每循环一次,判断一次 //PS:第二轮j从1->n,每循环一次,判断一次 //PS:第J轮j从j->n,每循环一次,判断一次 //PS:这样就遍历完序列中所有子序列的可能性 for(__int64 j = i; j < n; j++) //j从i开始到最后一个数字 { ThisSum += a[j]; if(ThisSum > MaxSum) //大于最大子序列之和则替换 MaxSum = ThisSum; } } return MaxSum; }
//PS:用分治法,先将原序列分成相似的两个子序列,这样可以得出一个结论,
//那就是最大子序列和要不在左子序列中,要不在右子序列中,要不在左子序列和右子序列的连接处
//对左子序列递归求最大序列和,对右子序列求最大序列和,再将左右子序列连接起来,求连接处的最大序列和
//最后比较就能求出整体最大序列和
__int64 MaxSubSum(__int64 a[],__int64 Left,__int64 Right) { __int64 Center; //中间元素 __int64 MaxLeftSum,MaxRightSum; //左右子序列最大序列和 __int64 MaxLeftBorderSum,MaxRightBorderSum; //左右边界最大序列和 __int64 LeftBorderSum,RightBorderSum; //左右边界序列和 if(Left == Right) //递归出口 if(a[Left] > 0) //当a[i]>0时,返回该元素 return a[Left]; else //否则返回0 return 0; Center = (Left + Right) / 2; MaxLeftSum = MaxSubSum(a,Left,Center); //递归求解左子序列 MaxRightSum = MaxSubSum(a,Center + 1,Right); //递归求解右子序列 MaxLeftBorderSum = 0; LeftBorderSum = 0; for(__int64 i = Center; i>= Left; i--) //求左边界最大序列和 { LeftBorderSum += a[i]; if(LeftBorderSum > MaxLeftBorderSum) MaxLeftBorderSum = LeftBorderSum; } MaxRightBorderSum = 0; RightBorderSum = 0; for(__int64 i = Center + 1; i <= Right; i++) //求右边界最大序列和 { RightBorderSum += a[i]; if(RightBorderSum > MaxRightBorderSum) MaxRightBorderSum = RightBorderSum; } return max(max(MaxLeftSum,MaxRightSum),MaxLeftBorderSum+MaxRightBorderSum); //返回整体最大序列和 } __int64 algorithm3(__int64 a[],__int64 n) //T(N)=O(NlogN),底数为2 { return MaxSubSum(a,0,n - 1); }
__int64 algorithm4(__int64 a[],__int64 n) //T(N)=O(N) { __int64 ThisSum = 0; __int64 MaxSum = 0; for(int i = 0; i < n; i++) //i从零开始到最后一个数字 { ThisSum += a[i]; if(ThisSum < 0) //当a[j]+...+a[i] < 0,则舍弃i之前的所有序列,从i后继续累加 ThisSum = 0; if(ThisSum > MaxSum) //求出当前序列的最大子序列和 MaxSum = ThisSum; } return MaxSum; }
__int64 Random(__int64 m,__int64 n) //指定范围内随机数
{
__int64 pos,dis;
if(m == n) //m=n则表示范围内只有一个数字
{
return m;
}
else if(m > n) //m>n则说明取[m,n]区间内数字
{
pos = n;
dis = m - n + 1;
return rand() % dis + pos;
}
else //m>n则说明取[n,m]区间内数字
{
pos = m;
dis = n - m + 1;
return rand() % dis + pos;
}
}
void MakeRandomSequences(__int64 m,__int64 n,__int64 num) //产生随机序列
{
ofstream filerandom("G:\\sequences.txt");
srand((int)time(NULL)); //根据时间产生相应种子值
for(int i=0 ; i < num; i++)
{
filerandom << Random(m,n) <<" ";
if(!((i + 1) % 10)) //数据量逢十换行
filerandom << endl;
}
filerandom.close();
}
int main()
{
//测试数据
// __int64 a[] = {4,-3,5,-2,-1,2,6,-2};
// __int64 n = 8;
// cout << algorithm1(a,n) << endl;
// cout << algorithm2(a,n) << endl;
// cout << algorithm3(a,n) << endl;
// cout << algorithm4(a,n) << endl;
// MakeRandomSequences(-1000,1000,100000); //产生随机序列
__int64 a[200000];
__int64 n = 0;
ifstream filesequ("G:\\sequences.txt");
if(!filesequ.is_open()) //打开失败处理
{
cout<<"Error opening file";
return -1;
}
while(!filesequ.eof())
{
filesequ >> a[n++];
}
filesequ.close();
//PS:测试只需要把调用算法注释去掉
// cout << algorithm1(a,n) << endl;
// cout << algorithm2(a,n) << endl;
// cout << algorithm3(a,n) << endl;
cout << algorithm4(a,n) << endl;
return 0;
}
相关文章推荐
- TCP/IP状态详解[转]
- Learn Gradle - CH 3 Java 快速入门
- bzoj4179: B
- 实现关闭ssh继续实施方案---tmux
- 二分图判定--黑白染色
- 《基于 FFmpeg + SDL 的视频播放器的制作》课程的视频
- 如何解决内网IP端口不通的问题
- 探索 == 快乐
- 插入排序
- genymotion The connection to adb is down, and a severe error has occured.You must restart adb and Ec
- HTML5基础03----HTML5元素简介及使用方法
- HTML5基础02----标签认识
- 数据段、代码段、堆栈段、BSS段的区别
- HDU 1598 ( find the most comfortable road )
- Cocos2d-x使用Luajit将Lua脚本编译成bytecode,启用加密
- 苹果5S A1528,5C A1526 升级移动4G网络教程
- BCB中的TCheckBox复选框
- 参数估计
- [多校2015.01.1010 容斥+迭代] hdu 5297 Y sequence
- Prod 函数