算法学习系列1——时间、空间复杂度分析

Big O notation(大O符号表示法)

O(1): Constant Complexity 常数复杂度;
O(log n ): Logarithmic Complexity 对数复杂度;
O(n): Linear Complexity 线性时间复杂度;
O(n²): N square Complexity 平方复杂度;
O(n³): N cubic Complexity 立方复杂度;
O(2n): Exponential Complexity 指数复杂度;
O(n!): space 阶乘复杂度;

对于复杂的的计算,只看最高复杂的运算;

如何计算时间复杂度

1.最常用的方式就是直接看函数,分析这段代码运行了多少次;
2.不考虑代码运行时带来的系数差异;

eg.

//O(1) 不论n为多好,只执行一次println
int n = 2000;
System.out.println("Hello-input:" + n);
//O(1) 不论n为多少,只执行3次println,切记没有O(3)的表示法
int n = 2000;
System.out.println("Hello-input1:" + n);
System.out.println("Hello-input2:" + n);
System.out.println("Hello-input3:" + n);

以上两段代码均是*O(1)*复杂度;

eg.

//O(n) 执行次数与输入n满足:(执行次数)=n的线性关系
for (int i = 1; i <= n; i++) {
	System.out.println("Hello-input4:" + i);
}
//O(n²) 嵌套循环中则执行次数与输入n满足:(执行次数)=n²的线性关系
for (int i = 1; i <= n; i++) {
	for (int j = 1; j <= n; j++) {
		System.out.println("Hello-input5:" + i "and" + j);
	}
}

上述代码第一段与n成线性关系,即O(n),第二段与n成平方关系,即O(n²)

eg.

//O(log(n)) 执行次数与输入n满足:(执行次数)=log(n)的对数关系
for (int i = 1; i <= n; i = i * 2) {
	System.out.println("Hello-input6:" + i);
}	
//O(k^n) 递归方法中执行次数与输入n满足:(执行次数)=k^n的指数关系
int fibo(int n) {
	if (n < 2) return n;
	return fibo(n - 1) + fibo(n - 2);
}

上述代码第一段与n成对数关系,即O(log(n)),第二段递归为指数关系,即O(kn)

 n小于10时几种复杂度差异不大,随着运行次数增大,指数、阶乘等复杂度会变得十分恐怖,所以注意算法的时间及空间复杂度,是非常有必要的,此处就不在附上时间复杂度比较图表了,随便一搜索就可以找到;

递归条件下如何计算时间复杂度

求第n个斐波那契数列
F(n) = F(n-1) + F(n-2)

int fibo(int n) {
	if (n < 2) return n;
	return fibo(n - 1) + fibo(n - 2);
}

 比如如果计算n=6的话,就要计算n=5与n=4,而n=5需要计算n=4和n=3,而n=4需要计算n=3和n=2,以此类推,最终都需要计算到n=1与n=0,就是说最后运算的状态树为2n,复杂度就是指数层级的。
 如果想要降低递归算法的复杂度可以可以加缓存,存储中间项(因为整个状态树中有较多重复计算项),或者直接采用循环方法;

常用的递归复杂度计算公式

  1. 二分查找 Binary search
    因为每次只计算一边,所以时间复杂度可以看为O(log n)
  2. 二叉树遍历 Binary tree traversal
    可以这么来看二叉树的节点每个都要访问,且仅仅访问一次,所以时间复杂度为O(n)
  3. 有序二维矩阵二分查找 Optimal sorted matrix
    一维数组的二分查找是O(logn),有序二维矩阵二分查找的时间复杂度为O(n)
  4. 归并排序 Merge sort
    时间复杂度为O(n log n),且排序算法的复杂度最优为O(n log n);

 上述复杂度均可通过Master Theory证明得出,比较复杂,有兴趣者可以自行查阅;

思考

  1. 二叉树遍历-前序、中序、后序遍历时间复杂度多少?
    看二叉树的节点每个都要访问,且仅仅访问一次,所以时间复杂度为O(n)
  2. 图的遍历:时间复杂度是多少?
    图的节点只访问一次,复杂度为O(n)
  3. DFS、BFS时间复杂度是多少?
    *搜索空间里的节点只访问一次,复杂度为O(n)

空间复杂度

如何计算空间复杂度

计算空间复杂度主要考虑以下两点:

  1. 程序中数组的长度
  2. 程序中递归的深度

 如果代码中开辟的空间为数组,那你的空间复杂度通常就是数组的长度
 如果开启了递归,那么代码的空间复杂度就是递归的深度
 如果二者兼得,那么选择二者的最大值

eg.

//本代码仅为示例讲解,并不保证可以完美运行
class Body{
    public String getSpace(int n, int m) {
        int[] space= new int[n];
        space[0] = 0;
        for (int i = 1; i < n; ++i) {
            space[i] = space[i - 1] * i;
        }
        for (int i = 1; i <= n; ++i) {
            int funder= m / space[n - i] + 2;
            for (int j = 1; j <= n; ++j) {
                funder += valid[j];
                int[] ant = new int[n];
                if (funder == 0) {
                    ant.append(j);
                    valid[j] = 0;
                    break;
                }
            }
            m %= space[n - i];
        }
        return ant.toString();
    }
}

 上述代码,运行次数做多,时间复杂度最高的部分就是嵌套循环,运行次数为n2次,那么该段程序的时间复杂即为O(n2)
 空间复杂度:可以看到代码开始部分实例化了一个数组 int[] space = new int[n] ,且程序内部没有递归发生,那么该段程序空间复杂度为数组长度,即为O(n)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值