###### tags: `learning` `algorithm` `neopolitan` # 演算法作業01 ## ch1 習題 5 求最大公因數 用輾轉相除法,迭代版,以pseudocode ```python= int gcd(int a, int b) { // 不用判斷大小與交換,會自己換 while (b != 0) // 處理b為零,或直到b為零 { int remainder = a % b; (a, b) = (b, remainder); // 相當於遞迴 } return a; } ``` 用輾轉相除法,遞迴版,用python實作 ```python= def gcd(a,b): if (b == 0): return a return gcd(b, a%b) # 呼叫自己 ``` ## ch1 習題 6 找最大和最小 共有n個數, 先倆倆比大小,於是要比n/2次,被分成比較大的那一組和比較小的那一組。 然後兩組內再兩倆比大小,於是比了n/2次。 但這次大的組只留大的,小的組只留小的。 比完之後大的組和小的組的大小都只剩原來的一半。 一直比,直到大的組中只剩最大的,小的組中只剩最小的。 如果n取很大又是二的次方數,這樣共要比n/2+n/2(1+1/2+1/4+1/8+...)會逼近1.5n次。 ```python= def min_and_max(S): # 把S分成大的組S_max和小的組S_min S_min = [] S_max = [] for i in range(len(S)//2): if S[i*2] >= S[i*2+1]: S_max.append(S[2*i]) S_min.append(S[2*i+1]) else: S_min.append(S[2*i]) S_max.append(S[2*i+1]) return S_min, S_max def my_min(S): if len(S) >1: S_min_min = [] for i in list(range(len(S)//2)): if S[2*i] >= S[2*i+1]: S_min_min.append(S[2*i+1]) else: S_min_min.append(S[2*i]) return my_min(S_min_min) # recursive else: return S def my_max(S): if len(S) >1: S_max_max = [] for i in list(range(len(S)//2)): if S[2*i] >= S[2*i+1]: S_max_max.append(S[2*i]) else: S_max_max.append(S[2*i+1]) return my_max(S_max_max) # recursive else: return S S = [10, 20, 30, 40, 50, 60, 70, 80] S_min, S_max = min_and_max(S) print(S_min) print(my_min(S_min)) print(S_max) print(my_max(S_max)) ``` ## 15 證明 $n^2+3n^3\in\Theta(n^3)$ + $f(n)=n^2+3n^3\in O(n^3)$ + 對於所有 $n\geq1$,顯然有 $n^2+3n^3\leq n^3 + 3n^3=4n^3$ ,故得證。 + $f(n)=n^2+3n^3\in\Omega(n^3)$ + 對於所有 $n\geq1$,顯然有 $n^2+3n^3\geq n^3$ ,故得證。 綜上所述,$f(n)=n^2+3n^3\in\Theta(n^3)$。 ## 18 證明 $p(n) \in \Theta(n^k)$ $p(n)=a_k n^k+a_{k-1} n^{k-1}+\dots+a_2 n^2+a_1 n^1+a_0$ + 先證 $p(n) \in O(n^k)$ + 因為不知道$a_k$以外的$a_{k-1},\ldots,a_{1},a_{0}$們的正負, 我沒辦法宣稱 \begin{aligned} a_k n^k&+a_{k-1} n^{k-1} + \dots+a_2 n^2 +a_1 n^1 +a_0 \\ \leq a_k n^k&+a_{k-1} n^{k} \;\;\: + \dots+a_2 n^k +a_1 n^k +a_0 \end{aligned} + 於是找出 $a_i \: (i=0,1,\dots,k)$ 中最大的$a_{max}$,我們就可以宣稱 $\forall n>1$ \begin{aligned} a_k n^k&+a_{k-1} n^{k-1} +\dots + \;\;\:a_2 n^2 + \;\;\:a_1 n \;+ a_0 \\ \leq a_{max} n^k&+a_{max} n^{k} \;\;\: +\dots + a_{max} n^k + a_{max} n^k + a_{max} n^k \\ = (k+1)& a_{max} n^k \end{aligned} + 再證 $p(n) \in \Omega(n^k)$ 取 $a_k>c=a_k/2$ ,解 \begin{aligned} (a_k-c) n^k&+a_{k-1} n^{k-1} + \dots+a_2 n^2 +a_1 n^1 +a_0 = 0 \end{aligned} 令最大的實數根為 $n_0$ (若沒有實數根則代表所有係數都是正的,則下方不等式顯然成立),對於$n > n_0$ \begin{aligned} a_k n^k&+a_{k-1} n^{k-1} + \dots+a_2 n^2 +a_1 n^1 +a_0 \geq c n^k \end{aligned} 綜上所述,$p(n)=\Theta(n^k)$。 ## 22 - Θ(n ln n) - Θ(lg n) < Θ((lg n)^2) < Θ(n) - 亞線性 - Θ( 5n^2+7n ) = Θ( n^2 ) - 次方 - Θ(n^2) < Θ(n^(5/2)) < Θ(n^3) - 次方 - Θ(n!) - 階層 - Θ(2^n!^) > Θ(n!) 比指數還快 - $n!≒n^{n+1/2}e^{-n}$ - 因為$\frac{d}{dn}2^{n!}=e^{(\ln2)(n!)}\ln2\frac{d}{dn}(n!)$所以比$n!$還快 - Θ(4^n^) - 指數 - Θ(n^n^) - 比階層快 - $Θ(n^n + \ln n) = Θ(n^n)$ - $Θ(5^{\lg n}) = Θ( n^{\lg 5})$ 指數 - $Θ(n!) = Θ(n\lg n + 0.5\lg n - n)=Θ(n\lg n)$ - $(\lg n)!≒(\lg n)^{\lg n+0.5} e^{-\lg n}≒n^{-1} \sqrt{\lg n}(\lg n)^{\lg n}=e^{-\lg n+0.5\lg\lg n+(\lg\lg n)\lg n}$ - ~~不太確定,應該是跟指數一樣快~~ - 比指數慢 - n^0.5^ 比線性慢 - e^n^ 指數 - 8n+12 一次線性 - 10^n^+n^20^ 指數 ## 25 時間複雜度除以效能等於耗時。 時間複雜度 / 效能 = 耗時 現在效能變1000倍。 (a) T(n) - 改變前 - 問題實例的大小 1000單位 時間複雜度 1000單位 時間複雜度1000單位 / 效能1000單位 = 1分鐘 - 改變後 - 問題實例的大小 1000\*1000單位 時間複雜度 1000\*1000單位 時間複雜度1000\*1000單位 / 效能1000\*1000單位 = 1分鐘 (b) T(n^3) - 改變前 - 問題實例的大小 1000單位 時間複雜度 1000^3單位 = 10^9單位 時間複雜度10^9單位 / 效能10^9單位 = 1分鐘 - 改變後 - 問題實例的大小 1000\*10單位 時間複雜度 10^12單位 時間複雜度10^12單位 / 效能10^9\*1000單位 = 1分鐘 (c\) T(10^n) - 改變前 - 問題實例的大小 1000單位 時間複雜度 10^1000單位 時間複雜度10^1000單位 / 效能10^1000單位 = 1分鐘 - 改變後 - 問題實例的大小 1003單位 時間複雜度 10^1003單位 時間複雜度10*1003單位 / 效能10^1003單位 = 1分鐘 ## 34 while-loop 裡面的主要block會執行k+(k-1)+...+2+1=k(k+1)/2次, 所以整個演算法是Θ(k^2^),也就是Θ(log(n)^2)。 ## 37 在 lg(n) 的時間複雜度求 x^n^ % p, 假設 n = 2^k^ ```python= def pow_Theta_lg_n(x, k, p): temp = x for _ in range(k): temp = ((temp % p) ** 2) % p return(temp) x = 3234 p = 1177 k = 1007 exam = pow_Theta_lg_n(x, k, p) - pow(x, 2**k, p) print(exam) ```