DSA
O O O记号
- O ( n ) O(n) O(n):上界,用的最多
- Ω ( n ) \Omega(n) Ω(n):下界
- θ ( n ) \theta(n) θ(n):确界,上界和下界的组合。
高效解
O ( 1 ) O(1) O(1)
- 不含转向(循环、调用、递归等)必顺序执行,即是 O ( 1 ) O(1) O(1).
O ( l o g c ( n ) ) O(log_c(n)) O(logc(n))
1.常数底无所谓
∀
a
,
b
>
0
,
l
o
g
a
n
=
l
o
g
a
b
⋅
l
o
g
b
n
=
Θ
(
l
o
g
b
n
)
\forall a, b > 0, log_an = log_ab \cdot log_bn = \Theta(log_bn)
∀a,b>0,logan=logab⋅logbn=Θ(logbn)
2. 常数次幂无所谓
∀
c
>
0
,
l
o
g
n
c
=
c
l
o
g
n
=
Θ
(
l
o
g
n
)
\forall c > 0, logn^c = clogn = \Theta(logn)
∀c>0,lognc=clogn=Θ(logn)
3. 对数多项式
4. 复杂度无限接近常数
∀
c
>
0
,
l
o
g
n
=
O
(
n
c
)
\forall c > 0, logn = O(n^c)
∀c>0,logn=O(nc)
有效解
O ( n c ) O(n^c) O(nc)
1.多项式
一般地:
a
k
n
k
+
a
k
−
1
n
k
−
1
+
⋅
⋅
⋅
+
a
1
n
+
a
n
=
O
(
n
k
)
,
a
k
>
0
a_kn^k+a_{k-1}n^{k-1}+\cdot\cdot\cdot+a_1n+a_n = O(n_k), a_k > 0
aknk+ak−1nk−1+⋅⋅⋅+a1n+an=O(nk),ak>0
2.线性
所有
O
(
n
)
O(n)
O(n)类函数
3.幂
4. 这类算法的效率通常认为令人满意的。
难解 O ( a n ) O(a^n) O(an)
- ∀ c > 1 , n c = O ( 2 n ) \forall c >1, n^c = O(2^n) ∀c>1,nc=O(2n)。
- 这类算法计算成本增长极快,通常认为是不可忍受的。
- 从 O ( n c ) 到 O ( 2 n ) , O(n^c)到O(2^n), O(nc)到O(2n),是从有效算法到无效算法的分水岭。
- 很多问题的
O
(
2
n
)
O(2^n)
O(2n)算法往往显而易见,然而,设计出
O
(
n
c
)
O(n^c)
O(nc)算法却极其不易。甚至,有时注定是徒然无功。
5.定理:2-Subset is NP-complete.
算法分析
复杂度分析的主要方法:
- 迭代:极数求和
- 递归:递归跟踪+递推方程
- 猜测+验证
级数
- 算数级数:与末尾平方同阶
T ( n ) = 1 + 2 + ⋅ ⋅ ⋅ + n = n ( n + 1 ) / 2 = O ( n 2 ) T(n) = 1+2+ \cdot \cdot \cdot + n= n(n+1)/2 = O(n^2) T(n)=1+2+⋅⋅⋅+n=n(n+1)/2=O(n2) - 幂次级数:比幂次高出一阶
∑ k = 0 n k d ≈ ∫ 0 n x d + 1 d x = 1 d + 1 x d + 1 ∣ 0 n = 1 d + 1 n d + 1 = O ( n d + 1 ) \sum_{k=0}^nk^d \approx \int_0^n x^{d+1}dx = \frac{1}{d+1} x^{d+1}|_0^n = \frac{1}{d+1}n^{d+1} = O(n^{d+1}) k=0∑nkd≈∫0nxd+1dx=d+11xd+1∣0n=d+11nd+1=O(nd+1) - 几何级数(a>1):于末项同阶
T a ( n ) = a 0 + a 1 + ⋅ ⋅ ⋅ + a n = ( a n + 1 − 1 ) / ( a − 1 ) = O ( a n ) T_a(n) = a^0 + a^1 + \cdot \cdot \cdot + a^n = (a^{n+1} - 1)/(a-1) = O(a^n) Ta(n)=a0+a1+⋅⋅⋅+an=(an+1−1)/(a−1)=O(an) - 收敛级数
- O ( 1 ) O(1) O(1)
- 未收敛,但有界:
h ( n ) = 1 + 1 / 2 + 1 / 3 + ⋅ ⋅ ⋅ + 1 / n = Θ ( l o g n ) h(n) = 1 + 1/2 + 1/3 + \cdot \cdot \cdot + 1/n = \Theta(logn) h(n)=1+1/2+1/3+⋅⋅⋅+1/n=Θ(logn)
l o g 1 + l o g 2 + l o g 3 + ⋅ ⋅ ⋅ + l o g n = l o g ( n ! ) = Θ ( n l o g n ) log1 + log2 + log3 + \cdot \cdot \cdot + logn = log(n!) = \Theta(nlogn) log1+log2+log3+⋅⋅⋅+logn=log(n!)=Θ(nlogn)
循环
-
算术级数: ∑ i = 0 n − 1 n = n + n + . . . + n = n ∗ n = O ( n 2 ) \sum_{i=0}^{n-1}n = n+n+ ... +n = n *n = O(n^2) i=0∑n−1n=n+n+...+n=n∗n=O(n2)for(int i = 0; i < n; i++) for (int j = 0; j < n; j++) O1operation(i, j);
-
算术级数: ∑ i = 0 n − 1 i = 0 + 1 + . . . + n − 1 = n ( n − 1 ) 2 = O ( n 2 ) \sum_{i=0}^{n-1}i = 0+1+ ... +n-1 = \frac{n(n-1)}{2} = O(n^2) i=0∑n−1i=0+1+...+n−1=2n(n−1)=O(n2)for(int i = 0; i < n; i++) for (int j = 0; j < i; j++) O1operation(i, j);
-
算术级数:for(int i = 0; i < n; i++) for (int j = 0; j < i; j+=2013) O1operation(i, j);
正确性的证明
- 不变性
- 单调性
- 正确性
封底估算
- 1 天 = 24 h r × 60 m i n × 60 s e c ≈ 25 × 4000 = 1 0 5 s e c 1天 = 24 hr \times 60min \times 60sec \approx 25 \times 4000 = 10^5 sec 1天=24hr×60min×60sec≈25×4000=105sec
- 1 生 ≈ 1 世 纪 = = 100 y r × 365 = 3 × 1 0 4 d a y = 3 × 1 0 9 s e c 1生 \approx 1世纪 == 100yr \times 365 = 3 \times 10^4 day = 3 \times 10^9 sec 1生≈1世纪==100yr×365=3×104day=3×109sec
- Φ = 1 + 5 2 = 1.61803... , Φ 36 = 2 25 \Phi = \frac{1+\sqrt5}{2} = 1.61803... , \Phi^{36} = 2^{25} Φ=21+5=1.61803...,Φ36=225
迭代与递归
递归跟踪:直观形象,仅适用于简明的递归模式;
递推方程:间接抽象,更适用于复杂的递归模式。
减而治之
分而治之
4. 递归子任务中常常重复计算,为了解决这个问题:有两个方案:
- 记忆(将已计算过实列的结果制表备查)
- 动态规划:颠倒计算方向:自顶向下递归,为自底而上迭代。
动态规划
- fib(n) = fib(n-1)+fib(n-2) . 递归:
O
(
Φ
n
)
O(\Phi^n)
O(Φn)
迭代: O ( n ) O(n) O(n)f = 0; g= 1; while(0 < n--){ g = g + f; f = g - f; } return g;
- 最长公共子序列(LCS)。
递归:
对于序列A[0, n], B[0, m],LCS(A, B)无非三种情况- 若n=-1,或m=-1.则取空序列("")
- 若A[n] = B[m].则取LCS(A[0,n), B(0,m)) + A[n] //减而治之
- A [ n ] ! = B [ m ] , A[n] != B[m], A[n]!=B[m],则在LCS(A[0, n],B[0, m))与LCS(A[0, n),B(0, m])中取更长者。
动态规划:
从0开始。
向量
填充因子= 实际所用容量/最大容量