本人演算法初學者,之前通過書籍學過一些基本演算法,但在刷演算法題的時候經常一道題做幾小時(感覺腦子裡有一個模糊的思路,但是實現起來無從下手),有時寫半天最後還跑不對,找bug找的懷疑人生,請問對於初學者是否正常?我應該怎麼快速提升自己做題時的代碼能力?


非常正常,首先要保持平和心態,其次是要找對方法。

我是去年12月重新撿起來leetcode刷的,剛開始刷的時候沒有一個總體概念,就按照leetcode給的題號刷,很快就發現刷了就忘,遺忘率非常之高,效率也很低下,一道題可能要1個小時才能寫出來,而且還是很多bug。刷到現在將近一年了,基本正常的medium題目拿來10-15min就可以bugfree。

建議按照標籤來刷,這樣你可以對某一類演算法題有比較深的認識。我把LeetCode題大概分成以下幾個主要類別:

  • 數組:簡單的很簡單,難的也很難,整體來說我覺得套路比較多,需要多刷和積累方法(trick比較多)
  • 鏈表:相對比較簡單,熟悉了鏈表的結構和基本操作之後,就可以刷的比較快。但是鏈表中的指針操作很多,需要「穿針引線」,考察心細
  • 棧:棧的題本身面試中也不多,一般就簡單的括弧匹配,逆波蘭表達式之類的(當然也有些數組題需要靠棧解決,比如尋找數組中每個元素右邊的第一個最大值)
  • 遞歸:
    • 樹:樹的題學習曲線比較久,如果你對遞歸能很快的理解,那麼樹的題也會刷的比較快,樹的遞歸問題無非就是定義好【遞歸結束條件】和【遞歸過程】就好
    • 回溯:回溯法也是一種遞歸方法,但是是相對比較暴力的解法,例如求排列組合問題,都需要用回溯法,掌握難度相對比較大,考察的也不多,如果覺得難可以暫時跳過
  • DP:相對靈活的一類題,面試中考察也比較多,當然都是常考的一些DP題,例如偷盜問題、揹包問題、最長公共子序列問題、最長上升子序列問題等
  • 貪心:考的不多,相對簡單,可以最後再看。


太正常不過了....

不管演算法能力在哪一個高度,都存在一道題至少幾個小時沒有一個確定的思路,實現起來無從下手的題目。

演算法題太多太多了,博大精深,建議你把演算法題分成5個集合:

  1. 一看就有明確的思路,並且能很輕鬆地實現,在實現過程中幾乎沒遇到任何障礙,甚至可以在紙上輕鬆寫完正確的代碼,越做越爽;(典型做出來時間:10分鐘)
  2. 一看就有明確的思路,但是實現的時候可能有一點喫力,但是在IDE的幫助下還是能在短時間內完成;(典型做出來時間:30~60分鐘)
  3. 一看就有模糊的思路,大致能猜到是哪幾種演算法可能能做出來這道題,實現的時候要翻一下以前的代碼或者相關的資料/博客;(典型做出來時間:60~120分鐘)
  4. 思路比較難想到,需要用不止一種演算法和數據結構結合,然後還要加點小小的優化,拼了老命也只能完成小一點的數據範圍... ;(典型做出來時間:120分鐘~inf)
  5. 這是一道全世界人都不知道有沒有正解的題目... (做出來大概可以發paper了)

你可以針對第二類和第三類的題目進行訓練學習,爭取把第三類挪到第二類,把第二類挪到第一類。第四類的話,用於你自己相當自信的時候給自己澆一盆冷水,意識到天外有天人外有人,第一類題用於自己非常消極,非常自卑的時候給自己一點自信。

第五類的話,如果你打算當一個理論計算機科學家的時候,可以去挑戰一下,人總是要有夢想的,萬一為國爭光了呢?


挺正常的,演算法很重要,但演算法也是學起來最難,最令人生畏的。

很多初學者在刷題的時候,思路飛來飛去,有時候以為是 動態規劃 的知識點,結果寫了半天代碼越寫越亂,最後一看 discuss 原來可以用 來解決。

其實,學演算法,刷題蠻幹是不行的,需要遵循科學的方法。

以下的經驗技巧,對於演算法新手,或大學沒有搞過ACM,想利用業餘時間提升演算法能力的同學比較有幫助,對於演算法高手和ACM大牛,可能不太適用,僅供參考。

演算法不是拼智商

演算法不是純粹拼智商的,智商高,就一定很厲害,不夠聰明,就一定不行。演算法是一種技能,是可以通過科學合理的方式訓練出來的能力。

智商的高低,當然會有影響,但這個先天因素無法改變,而科學合理的方法是大家都可以掌握的。

所以,首要的一點,是要意識到,演算法不是隻拼智商的,也是可以經由後天訓練習得的。

難度要循序漸進

有些同學喜歡上來就是幹,上來就是終極難度的題目,覺得自己只要做出最難的,其它的就迎刃而解了。這種急於求成的思想要不得。

演算法訓練是一個系統工程,需要循序漸進,太過於急功近利,反而容易因做不出難題而產生挫敗感,帶來反效果。

記得我有一個同事就做了次類似的事情。我們當時剛聽說有leetcode,就想上去試試,他上去後就挑了一道困難裡面還屬於比較難的題目,結果想了大半天也沒做出來,搞到自己特別沮喪。

你會發現這種做法效率很低,那道題目就算被做出來了,也不代表就可以解出其它的題目。

合理的做法是循序漸進。

如果你本身有基礎,熟練度高,那你刷簡單的leetcode應該是幾分鐘一題,幾分鐘一題的,花不了你多少時間。

如果你刷簡單都花費很長時間,說明熟練度不夠,就更應該從簡單開始。

然後過度到中等,再過度到困難。

這裡有個經驗之談。

目前國內大廠的演算法考察,基本不會超過leetcode 中等難度,上限難度基本都是leetcode 中等題裡面的中等難度(有點拗口,leetcode 中等難度裡面也有分檔次)。

如果你能夠再20分鐘內,做出這種難度的題目,國內大廠的演算法面試,基本可以暢通無阻。

按演算法分類來選題

選擇題目,除了在難度上要循序漸進,還建議在演算法上進行劃分。

基本的演算法數據結構是有限的。比如說鏈表,二叉樹,二分查找,動態規劃,哈希表。。。

我喜歡按演算法的分類來選題和刷題,比如一個時間段,只刷鏈表題,待刷得差不多的時候,接下來再刷二叉樹的題。。。

這種做法可以極大的提高刷題的速度,而且能帶來更好的效果。

一,持續地刷同個類型的題目,可以不斷地鞏固和加深理解。

二,可以更全面地接觸這個數據結構,演算法的各個變種,這會促使你對這個數據結構,演算法的理解更加全面和深刻,學習的效率會更高。

所以在一段時間內,持續地刷特定類別的題目,可以帶來事半功倍的效果。

當然,在能力已經比較強的時候,可以採用打散的方式來刷題,可以更好地鍛煉思維的靈活性和應變能力,但初期或能力較弱的時候,按分類選題,是比較好的。

解題三部曲

在具體做題的時候,可以採用以下三個步驟來進行。

拿到題目後,不要立馬開幹,想著下面的三個步驟,一步一步地來。

1. 看懂題目

看懂題目。有的題目很直接,直接告訴你要解決的問題是什麼,題目本身甚至都包含了對應的數據結構和需要用到的演算法;有的題目很隱晦,看了半天不知道它到底要解決什麼問題,可以用什麼演算法和數據結構來解。所以,看到題目後,一定要先確保自己理解清楚了。

我的一個經驗是,拿到一個題目後,看5分鐘,如果5分鐘之內看不懂,我就mark 下來,留到後面再做,要不很影響刷題的心情。

不過就leetcode 來說,這樣的題目不多。基本都能在再5分鐘內看懂。

2.分析,推導解法

分析推導題目的解法。

這個步驟要有意識地單獨拎出來,不要跟編碼步驟混淆在一起。也就是說,你在分析推導題目解法的時候,不要去想任何實現相關地事情,不用去想代碼怎麼寫,不用去想要用什麼庫,定義什麼變數,用多少層循環,都不要想,就想著在邏輯上,這道題目要怎麼解。

這樣做可以極大地降低你的心智負擔,使你高效地想出題目的解法。對於如何將想法變成代碼,可以留在下一個步驟,單獨來進行。

3.將思路轉換為代碼

當你確定題目都已經理解,並且分析推導出了題目的解法後,你才開始來思考如何將自己的思路轉換成代碼。是地,將思路轉換成代碼,可以是一個單獨地步驟,在實際工作中,其實也是很重要的一個能力。

有時,將一個思路轉換成演算法是很容易且自然的;但有時,有些思路轉換成代碼,是很有難度的事情。

或者你有體會,分析推導只用了不到十分鐘,結果代碼寫了半小時還寫不完整。

怎麼定義變數,保存狀態,用遞歸,還是用循環加輔助數據結構等等,都是將思路轉換成代碼要做的事情。

這個能力也需要刻意地去練習。

演算法的封裝

接下來,說點更細節的東西,演算法的封裝。

軟體設計裡面,最關鍵的思想就是抽象和封裝了。

其實解題也可以用到這種思路。

比如一道題目的正確解法是先排序,再進行二分查找,那你的腦子裡面只要記得,快速排序和二分查找,就可以了,不需要去想,快速排序和二分查找的具體實現。

就像我們在寫代碼的時候,遇到排序,查找,我們一般都直接使用了現成的函數庫,而不需要自己動手再寫一遍。這個是代碼層面封裝帶來的好處,思維層面的封裝也是一樣的道理。

這種封裝思想在做題的時候可以極大地減輕我們的心智負擔,使得自己的腦力可以發揮在問題的核心點上。

用封裝的思維去解題,你的解題能力會有快速地提升。

封裝的思想可以用於 「2.分析,推導解法」 的過程,在 「3.將思路轉換為代碼」 的過程,更是可以用語言內置的演算法函數,數據結構來直接實現,也使得從思路轉換到代碼的過程更加的直觀和自然。

在實際的面試或比賽中,除非有特殊說明,一般都可以放心地使用語言的內置演算法和數據結構。

然後你可能會問,對於像排序,查找這些基礎的演算法應該怎麼對待呢?我的建議是可以把它們當作重要演算法來刻意練習。

快排,快搜,堆排序等,我們可以稱它們為元演算法。

對於這些演算法的刻意練習。一開始的時候,要看演算法書的描述,確保自己理解了演算法的思路,然後嘗試自己實現一遍。

實在寫不出來,就參照或者直接抄。一個演算法花幾天的時間,大部分人都是可以理解並自己實現出來的。(排除一些特別難的,需要更長的時間)。

保持持續的動力

演算法能力的提升,是一個長期的事情,需要持續地學習和做題,而刷題又是個比較枯燥的過程,在遇到難題的時候,很容易產生挫敗感,甚至導致直接放棄。

所以這裡需要特別關注刷題時的正反饋。如果你老是無法解出某個難度或某個類別的題目的時候,你就要考慮降低難度,或者安排額外的時間,去更全面的複習特定的演算法和數據結構了。

注意不要死磕!演算法學習,特別講求方法和技巧,死磕非但磕不過去,還可能留下對演算法的心裡陰影,導致學習障礙。

總結

首先演算法不是隻拼智商的,是可以通過後天的刻意練習掌握的一種能力。

剛上手的時候,難度上需要循序漸進,最好能夠按演算法分類來刷題。

解題的時候,建議按這三個步驟來

1,看懂題目

2,分析,推導解法

3,將思路轉換為代碼。

在更細節方面,封裝的思想也可使用在演算法上面,可以極大地降低我們的心智負擔,提升解題的效率。

最後是要注意做題過程中的正反饋,確保自己能持續地做下去。

希望這裡分享的經驗技巧,能給大家帶來幫助:)

作者:大飛哥

原文鏈接:https://mp.weixin.qq.com/s/EoN9yzzapNqCeQp6lWdtYg

以下是我個人刷題過程中用到的資料和知識總結,感興趣的也可以點進去收藏一下。

程序員必須掌握哪些演算法??

www.zhihu.com圖標怎麼學好數據結構??

www.zhihu.com圖標刷 LeetCode 對於國內 IT 企業面試幫助大嗎??

www.zhihu.com圖標

我的刷演算法專欄:

和程序員小吳一起學演算法?

zhuanlan.zhihu.com圖標

推薦一本適合演算法初學者學習閱讀的書:)

推薦一本適合演算法初學者學習閱讀的書:)京東¥ 78.20去購買?

最後:

幫吳師兄一個忙,記得點個贊再走呀!

關注我的微信公眾號「五分鐘學演算法」,一起學演算法~

個人網站:http://www.cxyxiaowu.com


比較正常,特別是之前我刷medium一道題也得1個小時,而且很多時候還得偷看discussion

但是還是要堅持啊,做lc也一年了,我每天或多或少都會和小夥伴做題,統計了一下,非會員的medium全部做完,hard做了一半,總數差不多570吧(我基本不做easy)

現在情況來講,遇到一個題,哪怕是hard,我也絕不會沒有思路,medium往往能獨立做出來,這可能是一個上機恐懼症患者的最大的福音吧。

總之,當你覺得路途越發困難,有可能纔是成功的康莊大道。


建議每天花2-3個小時刷LeetCode,第一遍不用想太長時間,十分鐘沒思路就可以看看討論區的一些idea,然後再自己想和實現。第二遍刷的時候就要求自己能夠快速想到思路力爭做到bug free。當讓在這過程中最重要的是自己的思考和總結,很多套路和想法其實是一致的,可以一邊刷題一邊寫寫題解,多畫圖。


很正常,一開始刷演算法題都這樣,除非大神級別。對於我們這種普通人來說,接觸新事物總會有一個陣痛期,邁過去就好了。

看你的描述,「剛看了幾個基本演算法」,「debug 時間長」等等,你得自己回過頭看看,是自己對這幾個基本演算法瞭解的深不深?有沒有把演算法打出來自己運行一下?如果沒有實際運行就去做題,很可能導致自己寫的演算法就有問題--思路對,演算法選對,但是演算法有一步輸錯了,這就導致 debug 時間長。

從編程語言上看,你有沒有熟練掌握這門語言?會不會花了太長時間在語法問題上?

在最後說下選擇演算法題,你選的題目是不是在你能力範圍內?現在有不少分級刷題的網站,新手我一般比較推薦洛谷,打打新手村,熟悉語法和基本演算法,然後再按照上面的題目分類去學習新的演算法,逐個擊破。


不知道演算法大佬怎麼樣,我剛開始學的時候還不如你,劍指offer上的題目基本都做不出來,只能自己看答案然後慢慢理解,這樣堅持了半個月之後,才慢慢有了點感覺,刷起來就稍微輕鬆一點了。


最開始慢是很正常的,先刷基本的找找感覺,熟能生巧,比如鄙視鏈下游的leetcode


演算法就像當年高考數學倒數1,2題,物理倒數1,2題一樣,拉差距的,快不起來。


就跟玩魔方一樣


推薦閱讀:
相關文章