來自 JS101 的練習題,覺得邏輯還蠻神奇的,所以想記下來。
把每一次都當作第一次
其實一般直覺會想到的方法應該是:
- 把數列排序 => 由小到大
- 用 n 去從已經排序好的數列裡查值
所以用作弊一點的方法的話會是這樣子:
1 2 3 4 5 6 7 8 9
| function findNthMin(arr, n) { const sortedArray = arr.sort((a, b) => a-b) return sortedArray[n-1] } console.log(findNthMin([1, 2, 3, 4, 5], 2)) console.log(findNthMin([1, 3, 5, 7, 9], 3)) console.log(findNthMin([1, 1, 1, 1, 1], 2))
|
但這不是這篇文章想介紹的,想介紹的是另外一種思維:
- 從數列中找出最小值
- 把最小值從數列中刪除
- 重複步驟 1、2,直到重複 n 次為止
所以其實每一次都只是在找最小值,但重點在於 每一次都會把最小值移除 這個動作,這個動作會讓你下一次找到的其實是 次小值,接著是 次次小值,以此類推。
所以當你做了 n 次後,那一次的最小值就等同於第 n 個最小值了,挺神奇的吧?馬上來實作看看:
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
| function findNthMin(arr, n) { let min = null for(let i=0; i<n; i++) { min = Infinity let k = null for(let j=0; j<arr.length; j++) { if(arr[j] < min) { min = arr[j] k = j } } arr.splice(k, 1) } return min } console.log(findNthMin([1, 2, 3, 4, 5], 2)) console.log(findNthMin([1, 3, 5, 7, 9], 3)) console.log(findNthMin([1, 1, 1, 1, 1], 2))
|
雖然這解法比較複雜一點,但是還蠻有趣的!
用在排序上
這個方法其實也能用來做排序,參考下面的原始碼:
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
| function sort(arr) { let min = null const result = [] const total = arr.length for(let i=0; i<total; i++) { min = Infinity let k = null for(let j=0; j<arr.length; j++) { if(arr[j] < min) { min = arr[j] k = j } } result[i] = min arr.splice(k, 1) } return result } console.log(sort([1, 2, 3, 4, 5]))
|
就跟原本的做法差不多,但要特別注意 length
值會改變這件事情,不要像我一樣忽略了。