update chp1

This commit is contained in:
Shine wOng
2019-05-07 20:24:07 +08:00
parent 10c392df83
commit 548abe03db

View File

@@ -127,12 +127,62 @@ $$n^a + n^b <= n^a + n^a = 2 * n^a = O(n^a)$$
#### big $\Omega$ notation
big $\Omega$ notation是标志了算法运行时间的下,即最好情况,其定义如下:
big $\Omega$ notation是标志了算法运行时间的下,即最好情况,其定义如下:
_若存在函数f(n)和正的常数c使得在渐进的条件(n >> 2)下T(n) >= c·f(n)则可以认为f(n)给出了T(n)增长速度的一个下(最好情况)记T(n) = $\Omega$(f(n))_
_若存在函数f(n)和正的常数c使得在渐进的条件(n >> 2)下T(n) >= c·f(n)则可以认为f(n)给出了T(n)增长速度的一个下(最好情况)记T(n) = $\Omega$(f(n))_
#### big $\Theta$ notation
big $\Theta$ notation 是标志算法运行时间的平均情况,它也具有相似的定义:
_若存在函数f(n)和正的常数c1和c2使得在渐进的条件(n >> 2)下c1·f(n) < =T(n) <= c2·f(n)则可以认为f(n)给出了T(n)增长速度的平均情况记T(n) = $\Theta$(f(n))_
## 大O记号的运用计算
接下来是讨论大O记法应该怎么用具体说来就是如何计算大O记法下算法的时间复杂度。这又分为两种情况即迭代的计算和递归的计算。这是因为其他非迭代以及非递归的算法都是常数的时间复杂度在渐进的条件下可以忽略。
### 循环(迭代)算法大O的计算级数求和
其实,简单说来,就是分析各层循环执行的次数,然后求和。在渐进的条件下,就是级数求和问题。
所以要进行计算循环的时间复杂度,首先需要知道各种常见级数的求和方法,现列举如下:
+ 幂方级数: 比幂次高出一阶
- $T_2(n) = 1^2 + 2^2 + 3^2 + ... + n^2 = /frac{n(n+1)(2n+1)}{6} = O(n^3)$
- $T_3(n) = 1^3 + 2^3 + 3^3 + ... + n^3 = /frac{n^{2}(n+1)^{2}}{4} = O(n^4)$
- $T_4(n) = 1^4 + 2^4 + 3^4 + ... + n^4 = /frac{n(n+1)(2n+1)(3n^{2}+3n-1)}{30} = O(n^3)$
- ...
- $T_k(n) = 1^k + 2^k + 3^k + ... + n^k = /int_{0}^{n}x^k{d}x = \frac{x^{k+1}}{k+1}|_{0}^{n} = O(n^{k+1}))$
+ 几何级数: 与末项同阶
+ 收敛级数
+ 不收敛的级数
- 调和级数
- 对数级数 $\log1 + \log2 + \log3 + ... + \logn = \log(n!) = \Theta(n\logn)$
邓公说,计算的时候还是要灵活对待。最好可以画一个图分析,图上的每一个点代表一次循环,这样图的面积就是时间复杂度。
### 递归算法的大O计算
递归算法计算时间复杂度一般就有两个方法:
+ 递归跟踪(recursion trace): 通过跟踪到每一个递归调用,其总和的运行时间,就是算法的执行时间。
+ 递推方程(recurrence): 通过递推的表达式,写出不同规模问题运行时间的递推公式,通过求解递推公式,从而求解。
详情可见邓公的教材和讲义,有一些实例。
## 动态规划
动态规划是一种程序设计思想。即分析程序运行的时间复杂度以及其机理,从而不断地优化程序的执行时间。例如重新设计算法,以避免递归过程中的重复操作。或者直接化递归程序为迭代程序。
一般设计程序时,很难一开始就想出一个完美的解,一般人都是先想出一个易于实现的,可以运行的算法。但是其时间复杂度往往很高,例如递归的程序,由于逻辑简单,一般都容易想出一个递归的版本,但是递归的程序往往开销过大。
在有了一个可以运行的版本后,再分析已有程序的运行过程,对其进行优化,比如规避递归程序的冗余,或者利用栈模拟操作系统的函数栈,写一个非递归的代码。这整个过程就是动态规划。
关于动态规划,主要是有几个例子
+ 斐波拉契数
+ LCS
可以查看邓公的网课和讲义,我自己也有代码实现。