时间复杂度的差异测评!O(n)、O(nlogn)、O(n^2)、O(n^3)以最长子段和为例
来源:互联网 发布:7天阅卷网络 编辑:程序博客网 时间:2024/06/04 22:28
时间复杂度的差异测评
前言:
大家都知道,判断一个算法够不够好,一个很重要的标准就是算法的时间复杂度 ,同样一个问题,不同的算法执行的时间差异可以很大!这个就是时间复杂度导致的,关于时间复杂度的定义等,本菜鸟不予说明,大家可以参考各大算法或者数据结构书籍,里面有详细的解释,今天给大家带来的是不同时间复杂度算法运行时间的差异!
测试题目:
输入一个数据n(0,1000000),然后输入n个数据(-1000,1000),求出最长子段和。
样例输入:
5
-1 5 6 -3 7
样例输出:
15
题目分析:这是一个很经典的DP问题,大部分人都知道,这里将分别用O(n^3)、O(n^2)、O(nlogn)、O(n)算法求解。
O(n^3)算法:
这是一个很容易想到的算法(PS:当初我还没想出来。。。)。该算法使用3重循环,将所有子段的和求出,然后求出和最大的。
代码如下:
#include <cstdio>#include <algorithm>using namespace std;#define INF 0x3f3f3f3f#define MAX 101int a[MAX];int main(int argc, char const *argv[]){freopen("test.in","r",stdin);for(int i=0; i<MAX; i++){scanf("%d",&a[i]);}int ans = -INF;for(int i=0; i<MAX; i++){for(int j=i; j<MAX; j++){int sum = 0;for(int k=i; k<=j; k++)sum += a[k];ans = max(ans,sum);}}printf("%d",ans);return 0;}
O(n^2)算法:
这个算法用了一点数学知识,可以使用两重循环达到同样的效果。用s[i]储存前i-1个子段的和,然后使用两重循环用s[j]-s[i]求出所有子段的和,然后求出其中最大的。
代码如下:
#include <cstdio>#include <algorithm>using namespace std;#define INF 0x3f3f3f3f#define MAX 101int a[MAX],s[MAX+1];int main(int argc, char const *argv[]){freopen("test.in","r",stdin);for(int i=0; i<MAX; i++){scanf("%d",&a[i]);s[i+1] = s[i]+a[i];}int ans = -INF;for(int i=0; i<MAX; i++){for(int j=i+1; j<=MAX; j++){ans = max(ans, s[j]-s[i]);}}printf("%d",ans);return 0;}
O(nlogn)算法:
改算法使用的思想是分治法思想,即将一个大问题化成无数个小问题,无数个小问题的最优解得出来的就是大问题的最优解。用分治法将数组分为两部分,那么最长子串和只可能有三种情况,在左边、在右边、一部分在左边,一部分在右边。然后继续递归,即可求出解。
代码如下:
#include <cstdio>#include <algorithm>using namespace std;#define INF 0x3f3f3f3f#define MAX 101int a[MAX];int max_sum(const int &l, const int &r){//l为左端点,r为右端点int l_max, r_max, lm_max, rm_max, m_max, tmp, m;if(l == r){return a[l];}m = (l+r)>>1;//m为l和r的中点l_max = max_sum(l, m);//如果最长子段和在左边,l_max为和r_max = max_sum(m+1,r);//如果最长子段和在右边,r_max为和/*如果一半在左边,一半在右边*/lm_max = -INF, tmp = 0;for(int i=m; i>= l; i--){//lm_max代表从中间到左边的最长子段和lm_max = max(lm_max, tmp+=a[i]);}rm_max = -INF, tmp = 0;for(int i=m+1; i<=r; i++){//rm_max代表从中间到右边的最长子段和rm_max = max(rm_max, tmp+=a[i]);}return max(max(l_max, r_max), lm_max+rm_max);//返回最长子段和}int main(int argc, char const *argv[]){freopen("test.in","r",stdin);for(int i=0; i<MAX; i++){scanf("%d",&a[i]);}printf("%d",max_sum(0,MAX-1));return 0;}
O(n)算法:
这个算法应该就是这道题的最优解,使用动态规划进行求解。由这道题能得出一个动态规划方程:s[i] = max(s[i-1], s[i-1]+a[i]),即比较前i-1个子段和和前i个子段的大小,然后选取最大的。这里还要知道一件事,如果最长子段和等于小于0了,那么最长子段和重新计算。
代码如下:
#include <cstdio>#include <algorithm>using namespace std;#define INF 0x3f3f3f3f#define MAX 101int a[MAX];int main(int argc, char const *argv[]){int temp = 0;freopen("test.in","r",stdin);for(int i=0; i<MAX; i++){scanf("%d",&a[i]);}int ans = -INF;for(int i=0; i<MAX; i++){if(temp+a[i] < 0){temp = 0;continue;}ans = max(ans, temp+=a[i]);}printf("%d",ans);return 0;}
测试算法所用时间:
这里使用的数据为随机生成的大小为(-1000,1000)的数据。
一百个数据:
从上面的数据结果我们发现,所有算法的时间没什么差异,甚至O(n)算法时间要长。不要急,接着往下看!
一千个数据:
这下我们发现不同了吧,O(n^3)算法的时间为其他时间的30多倍。。。。。 O(n^3)完败!。。
不过其他算法还未分出胜负,咱们接着比。
一万个数据:
这时候O(n^3)已经运行不出来了。。O(n^2)也被甩了一大截。。。还有两个兄弟没分出胜负,咱们继续:
十万个数据:
这时候O(n^2)也运行不出来了。。O(n)小胜。。
百万个数据:
1000000的数据量,O(n)已经比O(nlogn)快了将近一倍,这下冠军已经产生了!O(n)!
测试总结:
根据上面结果,我绘制了以下表格:
第一列为时间复杂度,第一行为数据个数,中间数据为时间(秒为单位)。
100
1000
10000
100000
1000000
O(n)
0.035
0.034
0.041
0.049
0.339
O(nlogn)
0.028
0.023
0.032
0.069
0.580
O(n^2)
0.025
0.026
0.357
--------
----------
O(n^3)
0.023
0.655
------
--------
---------
现在我们可以发现了吧,一个好的算法有多么的重要!!所以大家一定要好好学习算法,这个才是编程的精髓所在!!!
- 时间复杂度的差异测评!O(n)、O(nlogn)、O(n^2)、O(n^3)以最长子段和为例
- 求数组的最大子段和(O(N^3)-->O(N^2)-->O(NlogN)-->O(N))
- 算法时间复杂度的表示法O(n²)、O(n)、O(1)、O(nlogn)
- (C#)找出数组中最大子序列之和,分别以O(N^2),O(NlogN),O(N) 这3种时间复杂度求解
- 最长递增子序列 O(n^2) 与 O(nlogn)
- 时间复杂度为O(m*n)最长公共子串
- 最长不下降子序列的O(n^2)算法和O(nlogn)算法
- 最长不下降子序列的O(n^2)算法和O(nlogn)算法
- O(n^3)、O(n^2)和O(n)求最长回文子串
- 以时间复杂度O(n)计算最大子序列和
- 求最大子列和(时间复杂度分别为O(n3) O(n2) O(n))
- 时间复杂度:O(1)、O(n)、O(n²)、O(nlogn)等是什么意思,白话文解释专业术语。
- 最长有序子序列 时间复杂度O(n^2)
- 时间复杂度为O(n)的排序
- 时间复杂度为O(n)的排序
- 算法时间复杂度的表示法O(n²)、O(n)、O(1)、O(nlogn)等是什么意思?
- 快速排序算法的时间复杂度为什么是O(NlogN),还有O(N^2)
- 最长递增子序列O(n^2)算法和O(nlogn)算法
- Referer setting for firefox
- “DLL劫持”技术的经典-----“LPK劫持者”木马!《LPK劫持者》
- 把悲伤封锁,把思念埋藏_伤感的回忆qq日志
- Android---Tween动画
- MAC下Android的Eclipse开发环境的搭建
- 时间复杂度的差异测评!O(n)、O(nlogn)、O(n^2)、O(n^3)以最长子段和为例
- 慌乱的表情,泄露了我的悲伤:伤感心情日志
- js实现日期比较
- javascript table 隔行变色
- 递归~逆波兰式
- C版本的二叉树
- Linux下的文本编辑器vim的使用
- mouse_event
- 程序员之路——一个老程序员对刚上大学的学弟学妹的忠告(转)