每次念這兩個詞都感覺很酷。
時間複雜度
簡單來說就是一個演算法平均需要多少「時間」來完成。
但時間並不是一個很好的指標,畢竟你家電腦跟 NASA 的超級電腦完全是不同等級的東西吧?所以時間上的落差一定很大,因此比較好的指標是用「執行次數」來解釋。
範例
假設要你在 1, 3, 4, 5, 9, 10 裡面找有沒有 9,最容易想到的演算法可能是:
演算法:從頭找到尾,看看有沒有。
輸出:有(第五個)
所以我們的演算法在 6 個數字時要看 6 次,換句話說就是有 n 個數字就要看 n 次。
這時候的時間複雜度就會是:O(n)
O(n)
是一個叫「Big O notation」的表示法:
把它想成是一種類似函數的東西就好,n
是你的輸入值,而 O(n)
的輸出結果代表「執行次數」:
O(1)
常數,不論 n 是多少都只需要 1 個步驟(最屌的演算法)
O(n)
當 n 是多少就要 n 個步驟(剛剛的範例)
O(n^2)
n 的 2 次方,每當 n 增加 1,就需要 n^2 步驟(n=1 => 1, n=2 => 4, … , n=10 => 100)
O(2^n)
2 的 n 次方,每當 n 增加 1,就需要 2^n 步驟(n=1 => 2, n=2 => 4, … , n=10 => 1024)
O(n!)
n 階層,每當 n 增加 1,就需要 n! 步驟(n=1 => 1, n=2 => 2, … , n=10 => 3628800)
實作
在知道時間複雜度後,我們可以來實作剛剛的演算法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| function hasNumber(numbers, searchNumber) { let result = false for (let number of numbers) { if (number === searchNumber) { result = true } } return result } const numbers = [1, 3, 4, 5, 9, 10] console.log(hasNumber(numbers, 10))
|
現在如果要查詢的數字變多了呢?如果沿用剛剛的演算法,時間複雜度會變成:O(n*m)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| function hasNumber(numbers, searchNums) { let result = [] for(let i=0; i<searchNums.length; i++) { for (let number of numbers) { if (number === searchNums[i]) { result[i] = true } } if (!result[i]) { result[i] = false } } return result } const numbers = [1, 3, 4, 5, 9, 10] console.log(hasNumber(numbers, [2, 3, 5, 9]))
|
詳細的步驟可以參考下面:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| i 0 number: 1 searchNums: 2 number: 3 searchNums: 2 number: 4 searchNums: 2 number: 5 searchNums: 2 number: 9 searchNums: 2 number: 10 searchNums: 2
i 1 number: 1 searchNums: 3 number: 3 searchNums: 3 number: 4 searchNums: 3 number: 5 searchNums: 3 number: 9 searchNums: 3 number: 10 searchNums: 3
i 2 number: 1 searchNums: 5 number: 3 searchNums: 5 number: 4 searchNums: 5 number: 5 searchNums: 5 number: 9 searchNums: 5 number: 10 searchNums: 5
i 3 number: 1 searchNums: 9 number: 3 searchNums: 9 number: 4 searchNums: 9 number: 5 searchNums: 9 number: 9 searchNums: 9 number: 10 searchNums: 9
|
空間複雜度
前面講時間,現在講空間,所謂空間複雜度是指:一個演算法平均需要多少「空間」來完成
在剛剛找數字的範例中,我們的演算法並沒有「儲存」任何資訊,所以空間複雜度就是 0。
然而,在前面實作部分中可以發現到當想查詢「多個數字」時,這套演算法的時間複雜度就會變成 O(n*m)
,應該有更好的作法才對?畢竟沒有必要每次都從頭找到尾阿!
以空間換取時間
與其每次都從頭找到尾,不如建立一個「表格」,要查數字時只需要「一個步驟」:查表格
有個很經典的例子:費式數列
範例
在 1, 3, 4, 5, 9, 10 裡面找有沒有 2, 3, 5, 9 這些數字:
演算法:
- 先建立一個數字表
- 把有出現的數字記下來(1, 3, 4, 5, 9, 10)
- 要找數字就直接查表格
輸出:
2 => 沒有(查表 False)
3 => 有(查表 True)
5 => 有(查表 True)
9 => 有(查表 True)
這時後時間複雜度就從剛剛的 O(n*m)
變成 O(n+m)
,但同時也利用了「空間」來儲存一些資訊,這就叫作「以空間換取時間」。
實作
一樣來實作一下這套演算法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
|
function hasNumber(numbers, searchNumbers) { let result = [] let table = {} for (let i=1; i<=100; i++) { table[i] = false } for (let i=0; i<numbers.length; i++) { table[numbers[i]] = true } for (searchNumber of searchNumbers) { if (table[searchNumber]) { result.push(true) } else { result.push(false) } } return result } const numbers = [1, 3, 4, 5, 9, 10] const searchNumbers = [2, 3, 5, 9] console.log(hasNumber(numbers, searchNumbers))
|
詳列步驟的話會是這樣:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| 1. 建立數字表格: { '1': false, '2': false, '3': false, '4': false, '5': false, '6': false, '7': false, '8': false, '9': false, '10': false, ... }
2. 把出現過的數字儲存起來: { '1': true, '2': false, '3': true, '4': true, '5': true, '6': false, '7': false, '8': false, '9': true, '10': true, ... }
3. 查表格 要找的數字:2,查表格 => false 要找的數字:3,查表格 => true 要找的數字:5,查表格 => true 要找的數字:9,查表格 => true
輸出結果:[ false, true, true, true ]
|
其實也有更快的作法,直接把「有出現的數字」記起來就好:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| function hasNumber(numbers, searchNumbers) { let result = [] let table = {} for (number of numbers) { table[number] = true } for (searchNumber of searchNumbers) { if (table[searchNumber]) { result.push(true) } else { result.push(false) } } return result } const numbers = [1, 3, 4, 5, 9, 10] const searchNumbers = [2, 3, 5, 9] console.log(hasNumber(numbers, searchNumbers))
|
步驟跟剛剛差不多,只差在表格建立的內容而已:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 1. 建立表格 { '1': true, '3': true, '4': true, '5': true, '9': true, '10': true }
2. 查表格 searchNumber: 3 searchNumber: 5 searchNumber: 9
輸出結果:[ false, true, true, true ]
|
以上就是關於時間複雜度與空間複雜度的簡單解說,謝謝觀看。