通俗算法教程01 - 開篇


大家好,好久沒有更新文章了,對不起大家。今天開始,我要寫另一個系列教程:算法。

開篇語

為什么要寫算法系列教程呢?因為最近剛看完《Algorithms, 4th Edition》這本經典算法書(電子書,中英版網上都有下載),有了些新收獲,覺得那些零散的知識點和經驗有必要也值得花時間好好整理一下。另外,我自己的算法知識應該還沒有達到去學好“機器學習”這門學科的程度,在寫教程的同時我也會不斷學習,我想和大家一起用算法這把鑰匙開啟“機器學習”這扇大門,去探索算法是如何讓機器“學習”的。

為什么要學習算法呢?我個人覺得最終目的還是為了提高自己的職場競爭力。算法的本質就是解決問題,所以學習算法本質上是在提高解決問題的能力,這是職場最重要的能力之一。另外,如果你想在面試中表現得更加出色,也要對算法有一定程度的掌握。

寫教程是很耗費精力的,而且學習算法是很枯燥的,但如果大家都能參與進來一起交流討論,那么整個過程就是不斷進行頭腦風暴、集思廣益的過程,這會是我繼續寫作的動力,這也會使得枯燥的算法學習之路變得有趣,並讓每個人收獲滿滿。

為了更方便大家利用碎片化的時間學習,更好的利用空閑時間在手機上閱讀,這個系列的每一篇文章我都會精心排版,而且每一篇文章閱讀時間都不會太長,會盡量控制在 6 分種以內(不包括思考的時間)。

這個系列會包含三部分內容。第一部分是算法基礎,由於算法和數據結構是密切相關的,所以也會講到一些數據結構的知識,但不會講太細。第二部分以常見的算法案例解析為主,包括解析一些算法面試題。第三部分是算法在機器學習中的應用,由於我自己也沒有學習過機器學習,所以這部分是探索式和交流式的,我會把我學到的用我理解寫出來,希望大家能參與進來一起交流。

這個系列的文章代碼選擇用 JavaScript 語言來編寫,程序語言都是相通的,我相信你看了 JavaScript 寫的算法實現可以很快用你熟悉的語言寫出來。但第三部分的機器學習相關內容,可能選用 Python,現在還不確定。

希望這個算法系列教程能幫助大家在今后的編程道路上得心應手。

開篇算法題:FizzBuzz

好了,我們今天以一個算法問題 FizzBuzz 來開篇吧。FizzBuzz 是一個非常典型的用來面試的算法題。下面是 FizzBuzz 的自然語言描述:

編寫一個程序,打印 1 到 100 中的數字,但能被 3 整除的變為“Fizz”,能被 5 整除的變為“Buzz”,既能被 3 整除又能被 5 整除的變為“FizzBuzz”。

一看是不是很簡單?確實很簡單。看完題,隨手就能寫出下面的代碼:

for (var i = 1; i < 101; i++) {
 if (i % 3 == 0) console.log('Fizz')
 else if (i % 5 == 0) console.log('Buzz')
 else if (i % 3 == 0 && i % 5 == 0) console.log('FizzBuzz')
 else console.log(i)
}

和需求吻合,好像沒什么問題。等等,仔細檢查,這段代碼問題大了,FizzBuzz永遠沒有輸出的機會,例如遇到 i=15 還是會輸出Fizz。這是初級程序員很容易犯的一個錯誤,拿到需求后直接就是一通寫,對需求的理解比較生硬,不容易考慮到上下文的關聯關系。糾正后的寫法是將第 4 行的 if 條件放到最前面:

for (var i = 1; i < 101; i++) {
 if (i % 3 == 0 && i % 5 == 0) console.log('FizzBuzz')
 else if (i % 3 == 0) console.log('Fizz')
 else if (i % 5 == 0) console.log('Buzz')
 else console.log(i)
}

這樣寫是對的,但如果是面試,這個答案只能算是及格。如何能做到優秀呢?我總結寫算法可以分為三個步驟:

第一步是實現,即按照需求把算法寫對了,讓程序能正確的運行;第二步是優化,即降低復雜度,讓程序運算更高效。第三步是美化,即讓代碼看起來美觀簡潔,這一步很多時候會靈活運用到程序語言本身的語法糖,但簡潔有時候會犧牲代碼的易讀性,這需要在實際場景中稍作權衡。

做到這三步,我覺得應對面試中的算法題就可以拿優秀了。

前面我們已經完成了寫 FizzBuzz 算法的第一步,我們再來做第二步:優化。既能被 3 整除又能被 5 整除,我們很自然會想到 3 和 5 的最小公倍數:15,能被 15 整除的數一定也是既能被 3 整除又能被 5 整除的。也就是說上面的第二行代碼可以只對 i 判斷一次(而不是兩次),下面是優化后的代碼:

for (var i = 1; i < 101; i++) {
 if (i % 15 == 0) console.log('FizzBuzz')
 else if (i % 3 == 0) console.log('Fizz')
 else if (i % 5 == 0) console.log('Buzz')
 else console.log(i)
}

我們再來看第三步:美化。上面我們寫這個算法用了 6 行代碼(包括大括號),如果要減少代碼量,能減少到多少行呢?這里給到 2 行的實現方案:

for (let i = 0; i < 100; )
 console.log((++i % 3 ? '' : 'Fizz') + (i % 5 ? '' : 'Buzz') || i)

這個實現來自 Reddit 。當然也可以寫成一行,但寫成兩行閱讀體驗更好。這段代碼很好理解,我就不解讀了,有疑問可以在留言區留言提問。

最后,對於 FizzBuzz 算法問題,你有其它的實現方案嗎?歡迎在留言區討論。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM