本文是在代码随想录的基础上总结
时间复杂度分析
什么是时间复杂度?
-
时间复杂度是一个函数,它定性描述该算法的运行时间
-
在软件开发中,时间复杂度就是用来方便开发者估算出程序运行的答题时间
-
算法问题规模为n,那么操作单元数量使用函数f(n)来表示
什么是大O
- 大O来表示上界的,当用它作为算法的最坏情况运行时间的上届,就是对任意数据输入的运行时间的上界
- 插入排序的时间复杂度为O(n2)
注意: 输入数据的形式对程序运行时间有很大影响,数据有序的情况下插入排序为O(n2),但是数据是逆序的话则为O(n2)
算法复杂度默认是一般情况,如下图所示
插入排序 | 一般情况:O(n2) | 最好情况:O(n) 有序 | 最差:O(n2) |
---|---|---|---|
快速排序 | 一般情况:O(nlogn) | 最好情况:O(nlogn) | 最差:O(n2 |
不同数据规模的差异
注意: 一般说O( )时,默认去掉常数项,因为当数据规模起来了后,常数对复杂度的影响并不是很大了。
但这不意味着O(n2)的时间复杂度一定比O(n)大,因为有常数项!!!
一般来说算法时间复杂度的排行:
O(1) < O(logn) < O(n) <O(n2) < O(n3) < O(2n)
O(logn)中log是以什么为底呢?
举例:log2n = log210 * log10 n 我们之前说了可以忽略常数项,所以底是什么对我们的意义并不是很大。
leetcode 中超时是怎么回事
leetcode上刷题经常会出现一种错误是“超时”,也就是程序运行超过了规定的时间,一般OJ(online judge)的超时时间为1s,如果你写的算法时间复杂是O(n2)这个时候你就要考虑换成O(n)了。
实现三个函数,时间复杂度分别为 O(n),O(n2),O(nlogn),:
void function(long long n){
long long k = 0;
for(long long i = 0; i< n; i++){
k++;
}
}
void function(long long n){
long long k = 0;
for(long long i =0; i < n;i++){
for(long long j = 0;j<n;j++){
k++;
}
}
}
//O(nlogn)
void function(long long n){
long long k = 0;
for(long long i =0; i < n;i++){
for(long long j = 1;j<n;j = j*2){
}
}
}
递归算法的时间复杂度
如果不了解递归算法时间复杂度的话,有的人写递归会成O(n),而有的是O(logn)
例如:求x的n次方
方法一:用for来做
int function1(int x, int n) {
int result = 1; // 注意 任何数的0次方等于1
for (int i = 0; i < n; i++) {
result = result * x;
}
return result;
}
// O(n)
方法二:递归
如果面试官问有没有效率更好的算法呢,此时可以询问一下能不能给点提示,面试官提示可以考虑一下递归算法
int function2(int x,int n){
if(n==0){
return 1;
}
return function2(x,n-1) * x;
}
// O(n)
递归算法的时间复杂度 = 递归次数 * 每次递归中操作次数
注意 : 上面的代码递归次数n,所以时间复杂度为O(n),乘法操作的时间复杂度是一个常数项O(1)。
int function3(int x, int n) {
if (n == 0) {
return 1;
}
int t = function3(x, n / 2);// 这里是把这个递归操作抽取出来
if (n % 2 == 1) {
return t * t * x;
}
return t * t;
}