要讲算法,算法复杂度就一定要明白。
想象一下,当面试官给你一道题目,你稍加思考,开始娓娓道来。。但是你从何讲起呢?
直接来讲算法思路未免太low,这个时候你要把自己深厚的功底抖出来,(:如果学习不是为了装逼, 那么学习还有什么意义)这个时候就要拿出理论:“这一题我有一个O(n^2)复杂度的解法, 这个方案还可以有一个log(n)的优化···TVT。 ”
从复杂度出发并不是为了装逼, 而是专业素养的体现,从算法复杂度的理论出发去思考问题,找出最优解才是解决算法题的正确姿势。
算法复杂度的计算有点时候会非常困难, 这篇文章会有一些理论的东西,不感兴趣就略过那些好了,反正也碰不到。
首先你要知道,并不是所有的问题都是有解,对于一个问题,也不是所有规模都可以解决。以下几个名词先记住:(理论 ··· TOT)
P类问题:多项式复杂度内可以被精确解决的,也是面试中的大部分问题。
NP问题:在多项式复杂度内不能被精确解决,但是可以被不确定机解决(不确定机还只是一个理论,并没有这样的东西。我们一般用随机+检查的方式来解决这类问题,这里检查程序的复杂度要是多项式复杂度)
NPC问题:没有多项式算法解决这个问题,并且所有的NPC问题可以互相归约,只要一个解决了,其余的都解决了。
NP-hard问题:符合NPC的定义,但是不属于NP问题,也就是没办法解决。TAT
什么是多项式复杂度?
复杂度分为时间复杂度和空间复杂度,多数情况下我们关心时间复杂度,空间复杂度也会被考虑。
首先你需要知道,普通计算机1秒钟到底能计算多少次?
综合考虑计算机的CPU和内存速度,1秒中大概可以计算10^8 (1e8)次。
当然啦,计算加法和乘法的速度明显是不一样的。所以这个”一次”中做什么并不是严格的,只是大概可以:
for(int i = 0; i < 1e8; i++){ ... }
给出几种复杂度的例子你就大概可以get了。
1. for(int i = 0; i < n; i++){
for(int j = 0; j < n; j++){
...
}
}
这样的,复杂度为O(n^2)。(循环内只做简单的运算, 如果内部处理有更大的复杂度也需要乘进复杂度中。)
2. for(int i = 0; i < n; i++){
for(int j = 0; j < n; j *= 2 ){
...
}
}
这样的复杂度就是O(nlogn), 这里的log一般都是以2为底。
在实际代码中,会有很多操作,比如给一些数组赋初值啊等等,我们可以得到一个复杂度的式子。
比如我们有一个n大小的数组,我们要初始化成1。然后我们对这个数组做了3次两层循环的操作。所以我们得到了复杂度的式子是:n + 3*n^2
这就是多项式复杂度。
在计算复杂度的时候,我们只关心最高次项, 也就是这里的3*n^2, 并且忽略常数,也就是3。 最后得到的复杂度是:O(n^2)
常用的算法都有固定的复杂度,掌握他们的复杂度,可以把握这种算法到底能解决多大的问题,也能因地制宜的正确的使用算法。
你可以写一个计算1+1 的for循环,看看你的电脑1s到底能跑多少次TWT
(其实你的编译器会把这种傻逼的行为优化掉,所以你最好每次计算的时候都算不一样的数。比如每次都计算i+i 的值)