大O表示法:算法的時間復雜度通常用大O符號表述,定義為T[n] = O(f(n))。稱函數T(n)以f(n)為界或者稱T(n)受限於f(n)。 如果一個問題的規模是n,解這一問題的某一算法所需要的時間為T(n)。T(n)稱為這一算法的“時間復雜度”。當輸入量n逐漸加大時,時間復雜度的極限情形稱為算法的“漸近時間復雜度”。
大小關系:
當n→∞時,\(ln^αn<<n^β<<a^n<<n!<<n^n\)(其中α>0,β>0,a>1)O(X)可以當成一個數進行運算,當所有式子運算結束后,查看數量級即可。
如 \(n^2*O(1)=O(n^2)\),\(4O(2^{k-1})=2^{k+1}\)等比求和公式
\[Sn={{a_1(1-q^n)} \over {1-q}}={{a_1-a_nq} \over {1-q}}\]
迭代程序
方程法
- 題目:
int i=1;
while(i<=n) {
i=i*2;
}
- 思路:
假設循環執行了k次,那么\(2^k\)≤n,則k≤logn,所以時間復雜度為T(n)=O(logn)
求和法
- 題目:
for(i=1; i<=n; i++)
for(j=1; j<=i; j++)
for(k=1; k<=j; k++)
x++;
思路:
\({∑_{i=1}^{n}∑_{j=1}^{i}∑_{k=1}^{j}1}=∑∑j=∑i(i+1)/2=O(n^3)\)一次方(求和∑)→二次方
二次方(求和∑)→三次方
遞歸程序
主方法
- 分治法主定理:T[n] = aT[n/b] + f(n),其中n為問題規模,a≥1 and b>1 是常量,並且f(n)是一個漸進正函數,也就是遞歸以外的計算時間,為了使用這個主定理,需要考慮下列三種情況:
- 如果f(n)=O(\(n^{log_ba-ε}\))(即 f(n)的指數小於\({log_ba}\)),對於某個常量ε>0成立(即 f(n)為\(n^{log_ba}\)的低階無窮大),那么T(n)=O(\(n^{log_ba}\))(即 時間復雜度取決於高階無窮大
) 如果f(n)=O(\(n^{log_ba}\))(即 f(n)的指數等於\({log_ba}\))(即 f(n)為\(n^{log_ba}\)的同階無窮大),那么T(n)=O(\(n^{log_ba}logn\))
如果f(n)=O(\(n^{log_ba+ε}\))(即 f(n)的指數大於\({log_ba}\)),對於某個常量ε>0成立,並且af(n/b)≤cf(n),對於某個常量c<1(n足夠大)成立(即 f(n)為\(n^{log_ba}\)的高階無窮大),那么T(n)=O(f(n))
- 如果f(n)=O(\(n^{log_ba-ε}\))(即 f(n)的指數小於\({log_ba}\)),對於某個常量ε>0成立(即 f(n)為\(n^{log_ba}\)的低階無窮大),那么T(n)=O(\(n^{log_ba}\))(即 時間復雜度取決於高階無窮大
- 基本步驟:
- a=?, b=?, f(n)=?,滿足主定理條件
- f(n)的指數>(=)(<)\(log_ba\),若大於,則判斷cf(n)≥a(n/b),(c<1)
- 故時間復雜度為O(?)
- 題目:
T(n)=3T(n/2)+\(n^2\) - 思路:
- 試試能不能使用主方法,a=3,b=2,f(n)=n^2滿足條件
- 看看滿足哪一種情況,由於\(log_23\)<2,且\(3n^2/4 < cn^2\)(c<1),滿足第三種情況,所以T(n)=O(n^2)
迭代法
- 基本步驟:題目T(n) = aT(n/b) + f(n)
- 根據題目,設n=\(b^k\)(這樣可以消除n/b對我們判斷的影響),S(k) = T(\(b^k\))(將原式子T(n)=T(\(b^k\))記為S(k)),則k=\(log_bn\),並將從S(k)到S(1)依次列出來,如:
令 n=\(5^k\), S(k) = T(\(5^k\)),則k=\(log_5n\),那么
\(S(k) = 6S(k-1) + 5^k\),\((j=0)\)
\(S(k-1) = 6S(k-2) + 5^{k-1}\),\((j=1)\)
...
\(S(1) = 6S(0) + 5\),\((j=k-1)\) - 將左端為S(k-j)的式子乘上\(a^j\)之后全部加起來,即
\(S(k)*a^0+S(k-1)*a^1+S(k-2)*a^2+...+S(1)*a^{k-1}\)
就消去了所有中間項,得到S(k)=...,如:
\(S(k) = 6^k S(0) + [5^k + 6*5^{k-1} + ... + 6^{k-1}*5]\)
\(= 6^k*Θ(1) + 5*Θ(6^k) = Θ(6^k)\) - 寫成T(n)的形式,即S(k)=T(\(b^k\))=T(n)=...(其中k=\(log_bn\)),如:
\(k=log_5n\)
\(T(n) = Θ(n^{ln6/ln5})\)
- 根據題目,設n=\(b^k\)(這樣可以消除n/b對我們判斷的影響),S(k) = T(\(b^k\))(將原式子T(n)=T(\(b^k\))記為S(k)),則k=\(log_bn\),並將從S(k)到S(1)依次列出來,如:
- 題目:
//漢諾塔問題,假定move()的時間復雜度為O(1)
void hanoi(int n, char x, char y, char z) {
if(n == 1) {
move(x, 1, z);
}else {
hanoi(n-1, x, z, y);
move(x, n, z);
hanoi(n-1, y, x, z);
}
}
- 思路:
- 首先寫出表達式:T(n) = 2T(n-1)+O(1) (即 你的問題規模分解成了2個n-1的問題規模加上執行了一次基本操作move()
- 試試能不能使用主方法,發現a=2,b=1,f(n)=O(1),不滿足b>1的條件,不能使用
- 采用迭代法,因為每次迭代n的數據規模減少1,到最后必然會有終點,即n==1。
T(n)=2T(n-1)+1
T(n-1)=2T(n-2)+1
聯立,得
T(n)=4T(n-2)+1+2
由數學歸納法,得
T(n)=2^(n-1)T(1)+1+2+4+8+...+2^(n-2)
又∵終止條件T(1)=1
∴時間復雜度為O(2^n)
綜合例題
一個算法所需時間由下述遞歸方程表示,試求出該算法的時間復雜度級別。
\[T(n)= \begin{cases} 1& \text{n=1}\\ 2T(n/2)+n& \text{n>1} \end{cases}\]
式中,n是問題的規模,為簡單起見,設n是2的整數次冪。
- 主定理:
a=2, b=2,f(n)=n滿足條件;
1=\(log_22\),故時間復雜度為\(O(nlog_2n)\)
迭代法:
設n=\(2^k\)(k≥0),則
\(T(2^k)=2T(2^{k-1})+2^k\)
\(T(2^{k-1})=2T(2^{k-2})+2^{k-1}\)
故,\(T(2^k)=2(2T(2^{k-2})+2^{k-1})+2^k=2^2T(2^{k-2})+2*2^k\)
由歸納法,得\(T(2^k)=2^iT(2^{k-i})+i*2^k\)
進而i取k時,得
\(T(2^k)=2^kT(2^{0})+k*2^k\)
即 \(T(n)=2^{log_2n}+log_2n*n=n(log_2n+1)\)
也就是\(O(nlog_2n)\)主定理起驗證作用,一般用迭代法確保滿分。
求 T(n)=2T(n/4)+n^2的非遞歸解並證明。
- 主定理:
a=2,b=4,f(n)=n^2滿足主定理條件;
2>log_42,cf(n)≥2(n/4)^2=n^2/8,(c<1)成立;
故時間復雜度為\(O(n^2)\)
- 迭代法:
設\(n=4^k\)(k≥0),則
\(T(4^k)=2T(4^{k-1})+4^{2k}\)
\(T(4^{k-1})=2T(4^{k-2})+4^{2(k-1)}\)
故,\(T(4^k)=2(2T(4^{k-2})+4^{2(k-1)})+4^{2k}=2^2T(4^{k-2})+2*4^{2(k-1)}+4^{2k}\)
\(T(4^k)=2^iT(4^{k-i})+2^{i-1}*4^{2(k-i)}+...+4^{2k}\)
\(4^{2k}\)為其最高階無窮大
i取k,得\(T(4^k)=2^kT(4^0)+2^{k-1}*4^{0}+...+4^{2k}\)
\(lim\)\(T(4^k) \over 4^{2k}\) = 1 = \(lim\)\(T(n) \over n^2\)
故時間復雜度為\(O(n^2)\)
某算法的時間復雜度可用遞歸式
\[T(n)= \begin{cases} O(1)& \text{n=1}\\ 2T(n/2)+nlgn& \text{n>1} \end{cases}\]
表示,若用O表示該算法的漸進時間復雜度的緊致界,則時間復雜度為?
- 迭代法:
- 只考慮 n=\(2^k\) 的子列, 換元之后把 T(\(2^k\)) 記成 S(k), 那么
\(S(k) = 2S(k-1) + 2^k * k\)
\(S(k-1) = 2S(k-2) + 2^{k-1} * (k-1)\)
...
\(S(1) = 2S(0) + 2\) - 把左端為 S(k-j) 的式子乘上 \(2^j\) 之后全加起來就消去了所有中間項得到
\(S(k) = 2^k S(0) + 2^k[k+(k-1)+...+1] = 2^k*O(1) + 2^k*Θ(k^2) = Θ(2^k*k^2)\) - 寫成 T(n) 的形式就是 \(T(n)=Θ(n*(ln n)^2)\)
由於 T(n) 是單調的, 考慮上述子列足夠推出漸進量級了
- 只考慮 n=\(2^k\) 的子列, 換元之后把 T(\(2^k\)) 記成 S(k), 那么
某算法的時間復雜度可用遞推式
\[T(n)= \begin{cases} O(1)& \text{n=1}\\ 6T(n/5)+n& \text{n>1} \end{cases}\]
表示,則時間復雜度為?
- 迭代法:
- 同樣的方法, 令 n=\(5^k\), S(k) = T(\(5^k\)), 那么
\(S(k) = 6S(k-1) + 5^k\)
\(S(k-1) = 6S(k-2) + 5^{k-1}\)
...
\(S(1) = 6S(0) + 5\) - 把左端為 S(k-j) 的式子乘上 \(6^j\) 之后全加起來就消去了所有中間項得到
\(S(k) = 6^k S(0) + [5^k + 6*5^{k-1} + ... + 6^{k-1}*5]\)
\(= 6^k*Θ(1) + 5*Θ(6^k) = Θ(6^k)\)
注意后面那堆求和是等比數列求和 - 換回去就得到 \(T(n) = Θ(n^{ln6/ln5})\)
- 同樣的方法, 令 n=\(5^k\), S(k) = T(\(5^k\)), 那么
某算法的計算時間為:T(n) = 4T(n/2) + O(n),其中 T(1) = O(1),求其時間復雜
度,寫出具體過程。
設n=2^k,則T(n)=T(2^k)
令S(k)=T(2^k)
\[ \begin{align} S(k) &= 4^kS(0)+O(2^k)+4O(2^{k-1})+...+4^{k-1}O(2) \\ &= 4^kO(1)+2^k+2^{k+1}+...+2^{2k-1} \\ &= 4^k+4^k-2^k \\ &= O(n^2) \end{align} \]
后面一大串其實是等比數列。