為什麼同樣是解決一個問題,別人就能想出演算法,而我卻絞盡腦汁,百般嘗試也不得其法?

1.有沒有相似的經歷,或是同感(看了人家的演算法恍然大悟,覺著真是天才,自己弱爆了),請談經歷與心得。
2.如果你就是那個大神,請說一下,你認為你為什麼能夠想出來?


別人總是覺得我代碼寫得快又好,然而他們不知道
最開始我們一起學習代碼的時候,老師布置的代碼作業,一個簡單的排序我要去圖書館找電腦找bug找一個下午,一個遞歸我要編三個下午,所有的題我得提前一周開始做,才能按時完成。我只認為自己做出來的東西才能拿出手。
大部分人只是該交的時候寫一下結果發現寫不出來,copy個別人的就完了。
最重要的就是找bug想思路的問題,那時覺得毫無錯誤就是出不來結果,只能一遍遍翻書,一遍遍看例題,以求能找到自己理解的不當和思維的漏洞。
有幾次事前沒做出來一直到交題的最後半小時才調好。
但是,每次用自己的思路和自己親手敲的代碼解決了問題,那種成就感都會把我所有的過程中全部的糾結和沮喪一掃而光。我痴迷於那種感覺,所以到現在,所有的代碼我都要親手完成。
犯過無數的低級錯誤,也全部憑自己的力量把他們找了出來。自己想出過各種低級演算法,也全都解決了問題,後來看一些高級演算法就可以瞬間了解他們的優點和思路。
現在我也算周圍人眼中所謂的大神。代碼有bug來找我,我一眼就看出來,因為我這種錯誤不知犯了多少遍。他們沒有思路的問題我幾分鐘就想好,因為類似的問題我想了不知道多少次,自己做了多少蠢蠢的演算法來解決,最後又突然在別處看到了其他解決方式,才知道自己多傻逼。
一年多了,周圍的人覺得他們絞盡腦汁也寫不出程序,我只能說,空手套白狼是不可能的。如今的情況是當年留下的禍根導致的。
寫代碼,思路是很重要的。而這些大腦方面的原因是經過不斷的錘鍊才可以提高的。
能寫出代碼的人,當遇到他們寫不出的代碼時,是不會停止嘗試和絞盡腦汁的。而你所謂的絞盡腦汁,可能只是你以為吧,到底是看著問題發獃多,抱怨自己做不出來的時間多,還是真正在想解決方法的時間多,你自己可以回憶一下。


一個人的命運,當然要靠自我奮鬥,但也要考慮自己的天賦。
靠前的答案都在強調自我奮鬥,奮鬥誠然重要,但我認為它被過分強調了。我覺得我有必要在這裡通過兩件事,告訴你們一點人生的經驗。

1.
在中學時期,信息學競賽省隊里有一位同學,相比不少做題成百上千的同學來說,他做過的題的數量是比較有限的,客觀地說,他的數據結構與演算法基礎在整個隊里算比較薄弱的。比如,省隊的平均水平實現Dinic或類似複雜度的演算法應該就是幾分鐘的事情,他只會寫最樸素的EK(當然這位同學在集訓期間個人的基本功不斷地提高,但我說的事情發生在這之前),所以在考察基本功的題目上,這位同學成績常不如多數人理想。然而,對於需要的演算法並非那種「核心只需套用經典演算法就能搞定的題目」,相比多數同學會取得比較差的成績,這位同學常常能通過即興想出的奇妙方法取得非常好的成績,甚至滿分。直到今日我一直相信,這真的是天賦差距,不是自我奮鬥可以彌補的

2.
如果你對NP完全性問題之間的歸約有所了解的話,你會發現其中有不少歸約是非平凡的,甚至理解歸約本身都不容易。當一位演算法領域的長者被問到這類歸約是如何想到的,背後的直覺來自哪裡時,他曾對我(以及我的同學)說:「這就是天賦」(譯自英文)。

我沒有說奮鬥不重要,沒有任何的這個意思,但一個人在演算法上的上限取決於天賦。


很快想出演算法的人,除了萬中無一的天才,就是曾經解決過類似問題或者讀過類似問題解法的。
比如,你沒有做過 programmatic typeface generation 不可能知道這裡面最煩人的是舍入誤差……


我改了答案,打算認真寫點感悟,因為我不是演算法大神,所以我舉得例子是別的方面的,但可以類比。

我覺得這裡面主要有幾點是比較重要的:

1. 經驗,踩過坑,知道這個。
2. 熟知某一塊知識點的方方面面。
3. 思維活躍,聯想豐富,觸類旁通。

==== 舉例

對於第1點,舉個例子:

在我司做移動端前端,做的多了,各種情況就接觸了,然後就各種坑就遇到了。曾經有個 https 證書問題導致在移動端頁面打不開,從來沒遇到過。解決這個問題各種測試、諮詢溝通花了半天多時間最終確認是 https 證書偽造的問題,與代碼無關。那麼我下一次遇到這個問題,不需要話半天時間調試,直接就可以定位 https 問題。

同樣道理,演算法方面,參照 @許浩 的答案,各種演算法都實現過,裡面的坑自然就知道了。那麼解決某個問題,馬上就可以解決。


對於第2點,舉個例子:

對於移動端調試工具和方法,我是進行過深入嘗試和總結的(移動端前端開發調試),所以對這塊就比較熟悉,各種調試工具的原理大體了解,對於 Charles 代理功能和方法比較熟悉。

通常前端都知道一些基礎調試方法:比如連接到電腦上,Chrome 附帶的工具可以調試 Android 4 系統的 Chrome 瀏覽器等等;iPhone 連接到電腦上,Safari 可以遠程調試 iPhone 的 Safari。但並不是所有移動端的場景都是這麼固定的。

有一次我妹子遇到一個移動端問題,是在內部的 app iPhone 版的 WebView 裡面的頁面出了問題。結果她就不知道怎麼調試了,因為只知道鏈接電腦可以調 Safari 裡面的,但這是 WebView 的頁面。這樣的話,光搜索學習調試知識就需要一些時間。

因為我對這塊比較熟,馬上就能想到用 Charles 代理到電腦上,起一個 weinre 服務,在 PC 上直接改 HTML 插入 weinre 腳本,就可以調試了。包括現在同事都經常來問我 Charles 的問題,其實我只是在去年某個周末,花了半天多的時間,把 Charles 的所有官方文檔看了一遍並實際操作了一遍。誰捋一遍,這些問題都能解決。

對於第3點,舉個例子:

當你各個基礎知識點掌握透徹之後,明白了原理,加一些聯想就會有更好的方案。舉一個很簡單的例子:你知道 iPhone 鏈接電腦之後,可以用 Safari 瀏覽器進行調試。然後 Xcode 附帶的 iOS Simulator 直接就在你電腦上,那麼你可以聯想到 Safari 瀏覽器應該也可以調試你 iOS Simulator 上的頁面。實際上也是可以的。那麼遇到要在 iOS Simulator 裡面調試網頁的時候,你馬上就打開了 Safari,而你同事不知道的話,可能要先搜索一下。

建立在知識點的基礎上,加一些聯想,就能解決更多未知的問題。

==== 總結

總結下來,還是多學習、多實踐、多踩坑、善於聯想。


別人叫我大神,我說我不是 。他們說你也別謙虛,就是你了。

一年級我和大家一起學C,我買了一本C prime plus照著學,每一個常式都抄過,每一個思考題都想過,每一個習題都上機做過。其他同學上課玩玩手機,下課打打遊戲。要交作業了網上copy一下,能過是運氣,大部分時候是調不通的。等到我代碼量上萬的時候,他們呢,有沒有一千的量?

學數據結構,學演算法。每一個結構都親手做過不止一次,編演算法的草稿紙都寫了幾大本。

學單片機,學微機原理,我去啃了整本《Intel彙編程序設計》,他們能把整本課本看完了嗎?

然後,他們問我,C指針是什麼?我說是內存的一個標籤。

他們又問我為什麼函數內創建的數值變數為什麼不能返回它的指針?我說函數作用域的自動變數生成在棧上,調用返回時當前的棧幀將會釋放,返回自動變數的指針存在破壞棧幀的風險。

他們說:哦,大神厲害。我說你也可以。

能上大學,大家智商之間都沒有多大差距,關鍵字在於態度。他們問我的這些問題我都碰到過,所以我可以一秒指出問題。練習越多,經驗越豐富。層次越高,看問題越明白。這都是大量的代碼和閱讀堆出來的。

為什麼同樣是解決一個問題,別人就能想出演算法,而我卻絞盡腦汁,百般嘗試也不得其法?
為啥我就能三分鐘解決而你要三十分鐘?

無他,唯手熟爾。


瀉藥
我看都答的差不多了
拋開無法企及的天賦外
對我來講
就一個字「熏」
熏多了就會了有靈感了就會了

什麼是熏?耳濡目染也
當然不止是聽
動手,做的多了罷了


一是需要一定的邏輯分析能力,二是需要多實踐,多鍛煉,多研究別人的思維方式。


這是正常情況,我經常這樣,感覺智商被碾軋。


有時候感覺被智商碾壓是沒辦法的


絕大多數人編程,都是要絞盡腦汁的。不同的是,有的人已經在上學的時候絞過了,而有的人工作了遇到問題才去絞。


因為大牛都是身經百戰,代碼寫的多了!
可以輕易想出演算法,並能發現代碼中的偏差(bug)


一句雞湯:

初學者和大師之間才最大差別,在於大師失敗的次數,遠遠超過初學者去嘗試的次數

the main difference between a master and a beginner, is that the master failes more times then beginner tries.


五個解決問題的普遍原理

第一、最好先決定那些最不費腦筋的事情來使問題簡單化.

第二、力圖用數學表達。

第三、不僅考慮未來,還要逆向思維.

第四、以多學科方式進行思考,最基本的理論。

第五、許多種因素的組合產生巨大效應。

——查理·芒格


去年的6月份,是我刷演算法和數據結構題目的第5個年頭,決定寫一本與之相關的書籍,這種慾望是逐漸強烈的,最後強烈到覺得自己可以承擔裸辭的一切後果,於是就從百度辭職,開始了一整年的寫書人生。今年9月,我寫的《程序員代碼面試指南--IT名企演算法與數據結構題目最優解》出版了,激動的好幾天沒睡,一路走來覺得好辛苦。現在剛剛重新開始了程序員生涯。


看到這個問題,我覺得特別想分享一下我這本書的自序,絕不敢說自己是大牛,因為見過的牛太多了。只是覺得感觸很深而已。


=========================================================

《程序員代碼面試指南--IT名企演算法與數據結構題目最優解》

自序

左程雲


我能出書挺意外的。

在6 年前的某一天,雖然我早就知道想進入那些大公司要靠「刷」代碼面試題來練習編寫代碼的能力。可是這一天卻不止如此,我突然有了心情去看代碼面試題長什麼樣子。於是收集了代碼面試的題目,越深入,我越有一種恐慌的感覺,因為感覺自己什麼都不行啊,對一個歸併排序(Merge sort)寫出完整的代碼都感覺挺費勁的,面對這個馮·諾伊曼發明的排序演算法,我真有底氣說自己是計算機專業的學生嗎?這種打擊並沒有持續太久,因為愛耍小聰明的人總會特別自信。我決定開始認真面對「刷」題這件事,但那時我根本不知道我即將面對什麼,更不要談有寫書的念頭。


我把課餘時間利用起來,心想:不就是「刷」題嗎?別人能寫出來,咱也能寫出來。起初的心態是我不服,我就想告訴自己能行。過程虐心是肯定的,經常半夜因為看到一個時間複雜度特別低的演算法自己真的不能理解而沮喪地睡不著覺。當時覺得找不到什麼資料能徹底讓我明白,書上講得太粗淺,網上的太散亂,代碼寫得看不懂。起初我「刷」題的時候無數次地想放棄,因為覺得這些都是什麼玩意兒!我為什麼放著好好的日子不過,去找這種罪受?可是我又不甘心,雖然我不懂很多解法,但是它們真的很有意思。


我將能買到的所有相關書籍上的所有題目全都研究了一遍,不管是中文的還是英文的,我都硬著頭皮「啃」。寫完每道題後,我都和書上的方法進行反覆對比。「啃」完了五六本書之後,距離我剛開始「刷」題已經過去16 個月了。寫書?別逗了,才剛看完啊。


「年輕人總會找借口說這個東西不是我感興趣的,所以我做不好是應該的。但他們沒有注意的是,你面對的事情中感興趣的事情總是少數,這就使得大多數時候你做事情的態度總是很懈怠、很消極,這使你變成了一個懈怠的人。當你真正面對自己感興趣的東西時,你發現你已經攥不緊拳頭了。」時常想起本科時的畢業設計指導老師——高鵬義老師說的這句話。說得對!對一個東西,如果你沒有透徹研究過,不要輕易說它不精彩。這不是博愛,而是對自己認真。


「刷」題代碼達到4 萬行的時候,我基本上成了國內外所有熱門「刷」題網站的日常用戶,此時我確認了一件事情,今天的代碼面試指導真的處在一個很初級的階段,這種不健全是全方面的。


例如:


經常看到一篇文章前後的語境是割裂的,作者經常根據之前的一個優良解法提出更好的優化方式,但整篇文章都不提之前的解法是什麼。這就導致初學者根本無法看懂;


幾乎所有的書籍都忽略例子帶來的引導作用,甚至還有不少書籍在闡述一個解法的時候只寫偽代碼,這就使得讀者在看懂意思和自己真正能寫出代碼之間其實還有很多的路要走;


代碼面試題目的特點是「多」、「雜」、「難」,從著手開始學習到最終達到自己想要的效果之間,自己對自己的評估根本無從談起。「慢慢練吧,學海無涯」成為主要的心態,這就難免會產生懷疑的情緒;


看見一道新的面試題時還是會無從下手,因為之前的學習無法做到舉一反三,對自己做過的題目缺乏總結和歸納;

難道「刷」題真的只適合聰明人玩?我不這麼看,既然大多數內容處在有待商榷的地步,那我就去學習原論文吧。


當時一個人在國外,記得在初冬的一個下午,「刷」題已經兩年之久,快吃晚飯的時候,我突然想起自己忘了吃午飯,就衝出家門去覓食。站在7-11 門前的廣場上,我拿著1.5美元的熱狗和75美分的咖啡,微溫的陽光撒在眼睛裡,遠遠地望著即將消失的一天。我停下來,把咖啡放在斑駁的石頭檯子上,手裡的熱狗挺好看,香腸和洋蔥都挺新鮮,清冷的空氣吹過來,卻讓我的心緒更亂。舊金山的天空五彩斑斕,讓漂泊者頭暈目眩。哭得跟個鬼似的我除了想家,哪裡敢想自己會出書呢?


當我意識到在網上很難搜到新鮮的題目時,我已經換了兩家公司,反覆實現了600 多道題目,關於刷題寫了差不多10 萬行代碼。原來只是為了找份工作而「刷」題這一初心早就忘了,變成了興趣並堅持了這麼久,我自己也感到意外。更奇怪的是,我已經完全樂在其中,同時交流慾望越來越強,時常和同事們展開這方面的討論。發現很多書上的解法不是最優,很多題目其實和同事們討論的做法更好,發現高手特別多,但好像都懶得動筆。


有一天,我看到自己寫的題目,想到自己那些抓心撓肝的日子,突然覺得要不出書吧?我已經離不開這種感覺了,如果這不是真愛,那什麼才是呢?這不是一個勵志的故事,是一個愛「刷」題的人決定把很多最優解講出來,就這麼簡單。


====================================================


所以,真的不是「別人就能想出演算法,而我卻絞盡腦汁,百般嘗試也不得其法」,而是你絞的不夠。


你只看到我雲淡風輕道出最優解時的瀟洒從容,卻沒看到我半夜三更一次又一次面對WA時的迷茫無助


EE的本科狗,別人總覺得我是大神,不懂得題和知識總來問我,之前考完考試還問我考怎麼樣後來都乾脆不問了,我想說的是我tutorial的題目第一遍完全不懂看著答案半抄半算一遍,第二遍只對比最終答案自己回憶想思路,第三遍什麼都不看自己做經常發現答案有小錯誤,而他們大部分都只做到我的第一遍。上學期學了一門課叫control system身邊大部分朋友都買了書我也買了,書有點厚13章600多頁,他們不知道這本書我做的筆記可能比他們看了這本書的內容都多。


你遇到以前解決過的類似問題時,能從容搞定。別人也覺得你特神奇,咋一下子就解決了。


總結起來就一句話:你必須很努力,才能看起來毫不費力


例如NOIP、ACM競賽方面,大牛總是可以一眼看出題目所應使用的演算法,我自己總結一下無非有以下單點
1、貨多、會的演算法一定要多
學演算法是入門的初步,這裡說的學,不單單指會拿著代碼用,而是要能理解:比如你知道快排,但不知道分治,那就不能算理解。演算法有很多,基礎的有深搜、廣搜、各種剪枝、模擬、貪心等。圖論里有floyed、dijstra、SPFA、Bellmanford、kruskal、prim、網路流、拓撲排序等(太多了、羅列常用的)。動態規劃也是非常常用的方法,數據結構方面相比比較難學,有堆、棧、並查集、二叉查找樹、紅黑樹、hash等很多。
2、題多、刷過的題目要多
從以前宇智波帶狗大神開設的vijos,任青大神開設的rqnoj(相信這兩個肯定有人老人知道,快上古時期了),再到現在各種在線題庫PKU,leetcode,geeksforgeeks,一畝三分地,mitbbs, hackerrank, lintcode, ninechapter, topcoder,能刷的題庫有很多,而且大多題目討論組裡都有答案詳解,多做題neng很好提升思維能力。
3、想多、思考的內容要多
一定要積極去思考,腦力勞動要活躍,不想演算法會自己跳出來嗎,想的太少,看你隊友不錘你!

集中精力腦力勞動真的很累,比賽一般都有帶麵包牛奶,出了試場,就一個字:餓!



很多人演算法厲害,其實不複雜
1:非常細緻的進行了調查,發現根本問題。
2:平時閱讀廣,積累了很多同屬性,同行業,跨行業,各種各樣的素材,素材豐富。

當有了細緻的調查,了解了根本問題後,根據以往的積累,你的大腦中就會出現很多演算法。


推薦閱讀:

蒙特卡羅演算法是什麼?
有哪些令人拍案叫絕的演算法?
大公司筆試面試有哪些經典演算法題目?
ACM 中常用的演算法有哪些?
如何在三角形(比如正三角形)里隨機取點?

TAG:互聯網 | 前端開發 | 演算法 | 編程 | 信息技術(IT) |