你不須要成爲一個數學天才才能成爲一個優秀的程序員,可是有一些技巧你能夠添加到你的問題解決包中,以提升你的算法的性能,並在技術面試中給人留下深入的印象。 在本教程中,您將學習如何用一個簡單且容易記住的等式來求和一系列從 1 到 n 的連續整數。這個等式對於將一個函數從 O(n)重構爲 O(1)的複雜度頗有用.javascript
你怎麼把這些數字加起來?前端
[1,2,3,4,5,6,7,8,9,10]
複製代碼
你的第一個想法是採用「蠻力」方法嗎?java
1 + 2 = 3
3 + 3 = 6
6 + 4 = 10
10 + 5 = 15
15 + 6 = 21
21 + 7 = 28
28 + 8 = 36
36 + 9 = 45
45 + 10 = 55
複製代碼
這沒什麼問題,你可能不須要紙筆或計算器就能到達那裏。 若是數組包含 100、1,000 或 1,000,000 個元素,該怎麼辦?程序員
咱們能夠很容易地編寫一個 for 循環來自動添加咱們的系列:面試
const nums = [1,2,3,4,5,6,7,8,9,10];
const sumHarder = arr => {
let sum = 0;
for (let i = 0; i < arr.length; i++) {
sum += arr[i];
}
return sum;
}
const result = sumHarder(nums);
複製代碼
再稍微優雅一點, 你可能會使用 reduce算法
const nums = [1,2,3,4,5,6,7,8,9,10];
const x = nums.reduce((a,b) => a+b);
複製代碼
這就解決了求和的問題。數組
爲何?bash
咱們的函數須要對每一個輸入執行一個操做,因此咱們的算法的階數是 O(n)或線性時間複雜度。函數
必定有更好的辦法!性能
與其用蠻力方法解決,不如來看看如何用算法來解決這個問題呢?
再看一下咱們的數組。咱們能夠用別的方法求和嗎?
[1,2,3,4,5,6,7,8,9,10]
複製代碼
當您對它進行求和的時候,您極可能是從一端開始,而後朝着另外一端工做。
或者你可能從結尾開始,而後往回算,就像這樣:
10 + 9 = 19
19 + 8 = 27
27 + 7 = 34
34 + 6 = 40
40 + 5 = 45
45 + 4 = 49
49 + 3 = 52
53 + 2 = 54
54 + 1 = 55
複製代碼
若是咱們把前面開始累加和後面開始累加, 結果會怎麼樣?
注意到什麼嗎?
若是咱們對錶中每一行的和求和,就獲得 11 的倍數。
有趣, 若是咱們從兩端開始,而後逐漸過渡到中間呢?
1 + 10 = 11
2 + 9 = 11
3 + 8 = 11
4 + 7 = 11
5 + 6 = 11
複製代碼
看到規律了嗎?
咱們有五對,每對 11 求和。這些對的乘積,就是 55。
可是若是你不知道數組的長度,你怎麼作這個計算?
咱們仍然會建立對,可是咱們將使用一個變量 n 做爲數組長度的佔位符。
1 + n = (n + 1)
2 + n -1 = (n + 1)
……
複製代碼
將數組中的第二個元素與倒數第二個元素配對。第二個元素是 2 倒數第二個元素是數組的長度減 1,因此是 n-1。
2 + n -1 的和是多少?
n+1
複製代碼
那咱們繼續
3 + n - 2 = n + 1
4 + n - 3 = n + 1
5 + n - 4 = n + 1
複製代碼
在某個點咱們會到達數組的中值。這個值是 n / 2。中位數是 5,也就是 10 除以 2 的商。
n / 2 * (n + 1)等於多少?
n ( n + 1) / 2
複製代碼
好了, 咱們把上面的規律找到了, 接下來咱們將 10 代入上面的方程.
10 ( 10 + 1) / 2 = 55
複製代碼
真棒! 咱們獲得咱們想要的結果了.
可是!
若是數組的長度是偶數,這種方法就能夠很好地工做。但若是是奇數呢? 若是咱們的數組包含奇數個元素怎麼辦? 以下:
[1,2,3,4,5,6,7,8,9]
複製代碼
咱們按上面的套路繪製出高低值對, 咱們會發現一個孤獨的中位數.
1 + 9 = 10
2 + 8 = 10
3 + 7 = 10
4 + 6 = 10
5
複製代碼
5 是多少?它是咱們對的和的一半。換句話說,中位數是 n + 1 的和的一半。
咱們能夠把它寫成方程來肯定中值:
(n + 1) / 2
複製代碼
看起來熟悉嗎? 若是咱們知道中值,下一步要作什麼?
咱們只須要將這個值乘以數組的長度。
n(n + 1) / 2
複製代碼
無論數組長度是多少,均可以使用這個數組來解決求和問題. 這個等式在幫助咱們提升算法效率方面是很是有用的。
咱們再來看看上面的函數。咱們如何重構它來改進它的算法複雜度?
咱們只需將等式轉換成 JavaScript!
const sumSmarter = arr =>
arr.length * (arr.length + 1)/2;
複製代碼
上面函數的算法複雜度下降成 O(1) 了. 無論數組的長度如何,咱們的函數老是執行相同數量的操做。
在本教程中,您學習瞭如何用一個簡單且容易記住的等式來對一系列連續整數求和。
咱們在面試的時候, 面試官偶爾會問, 請寫出從 1 到 100 的累計求和. 經過上面的講解, 相信你至少知道如何去下降算法複雜度.
在平常的編碼中, 咱們能夠經過一些找規律, 套公式下降算法複雜度~ 用起來吧
翻譯原文地址: [https://dev.to/nielsenjared/improve-your-algorithms-with-this-simple-equation-3g1c]