1. 引文
我们看标题,一个是时间一个是空间,这让我们想到前面我们说算法的目的就是高效率低储存,也确实如此,我们这章就是来计算我们时间上的效率,空间上的储存。
2. 算法的时间复杂度
2.1 如何分析算法的时间效率
为什么我们要分析时间效率呢?
对于同一个问题有很对的算法可以解决,但是这么多算法我们怎么评价哪种算法更好呢?一个好的算法我们首先要满足正确性,可读性和健壮性,满足这三个的情况下,我们主要就是判断算法效率的优劣来进行选择,算法效率又分为时间效率和空间效率。(对应我们讲的时间复杂度和空间复杂度)。
时间效率是算法运行时所耗费的时间,空间效率是算法运行过程中额外耗费的存储空间。

电脑的配置会影响我们的计算,所以我们都是采用事前估算的方法来分析。

实例:

这里面的重点要注意的就是循环,循环的执行次数是耗时的关键,为什么第6句会执行了N+1次呢?是因为当i>N时,也会进行一次判断,然后跳过循环;消耗的时间我们就先这样代替。

语句的消耗时间是和电脑配置挂钩的,这本身与算法是无关的,所以我们将每一句的耗时默认为一样的,为了方便计算我们都是默认为1,这样我们的事前估算只与执行次数有关系,时间效率就是执行次数之和。
2.2 时间复杂度的渐进表达式
这个渐进表达式可以说是我们高中学习的一种极限的思想,大学高数中也有讲过。

这就是一种抓大头的思想,我们只关注量级最高的,因为随着规模增加,小量级的影响会变得很小。


我们前面说了计算时间复杂度就看执行次数,那我们在数执行次数的时候我们就只需要关注循环语句即可,其他的常数项都是可以省略的。

这其中的对数又有些特别之处:

因为对数有换底公式,所以我们看见的对数形式有很多种。
2.3 时间复杂度的经典案例分析
2.3.1 O(N)级

这就是一般的一层循环,就是N级。
2.3.2 O(N²)级
我们前面讲过一个排序方式------冒泡排序,冒泡排序的比较和交换次数是一个1到N-1等差数列,f(N)=(N*(N-1))/2

这里的时间复杂度就是T(N)=O(N²)。
2.3.3 O(N³)级
MatrixMultiply这是一个计算矩阵相乘并打印结果的算法,这其中相乘是N³级,打印时N²级,我们只保留最高阶项。

这里的时间复杂度就是T(N)=O(N³)级。
2.3.4 O(logN)级

这与我们平常的循环不同的地方就是调整部分不是平常的i++而换成了i*=2;求复杂度我们都是可以假设来求,这里我们假设循环了x次,循环结束的条件是
时间复杂度T(N)=O(logN)。
2.3.5 O(1)级

这个是循环打印程序,最多循环打印100次打印前100个数;这个只有常数项的情况时间复杂度T(N)=O(1)。
2.3.6 O(N+M)级

这是两个循环打印程序,第一个循环打印M次,第二个循环打印N次,执行次数f(M,N)=M+N,但是我们不知道这两个那个更大,所以T(N+M)=O(max(M+N))或者T(N+M)=O(M+N)。
2.3.7 递推算法


2.4 空间复杂度的渐近表达式
空间复杂度和时间复杂度一样,都是采用事前估算的方式。

这其中字节的大小和编译器的有关,例如我们之前的指针在32位的情况下占4个字节,64位的情况下占8个字节,所以我们估算的时候默认每个变量的大小都是一样的,所以我们的空间复杂度就只看变量的个数。

我们空间复杂度是用S(N)来表示;注意:空间复杂度是算法因设计思路所需的额外开辟的空间,并不是变量的空间就代表空间复杂度。
2.4.1 O(1)级

算法申请了常数个变量,所以空间复杂度为S(N)=O(1)。
2.4.2 旋转数组时间复杂度O(N²),空间复杂度O(1)

时间复杂度T(N)=O(N²),空间复杂度是算法需要额外开辟的空间这里开辟的是常数,所以空间复杂度S(N)=O(1)。
2.4.3 旋转数组时间复杂度O(N),空间复杂度O(N)
如果我们采用新的思路,用空间来换时间,我们计算机的空间还是很大的,重点就是时间,我们可以使用空间来换取时间。
开辟⼀个额外的跟nums⼀样大的临时数组tmp,将nums的后k个数据挪动到tmp的前k个位置,再将nums前n-k个挪动到tmp的后n-k个 位置,再将tmp数组中的值拷贝回到nums数组。

光听思路就很容易判断出时间复杂度T(N)=O(N),空间复杂度S(N)=O(N)。

2.4.4 递归算法


3. 总结
我们对程序的评价就是从时间和空间两个方面来评判的,计算机的空间是很大的,所以我们重点就要关注时间,我们常常需要使用空间来换时间,我们后续还需要勤加练习达到快速判断的水准。
