刷題想要做到bug free要培養怎樣的思維?

每次處理String的for循環邊界超級討厭,感覺相關問題基本都不能一遍過,雖然很多人說細心細心,但是我最近在想是不是我思維方式的問題(難道我思維太跳了?),每次看別人一遍就bug free的代碼感覺很自然很流暢看起來似乎很容易,但是每天刷題我覺得都在刷新自己智商下限,雖然說收穫也有。各位有什麼好的經驗可以分享么。當然String只是一個例子。。其實我就是最近刷題學演算法人都炸了。。想知道大家思考問題的方式。。


摘某Google員工的一段話吧,來源是 白板編程淺談——Why, What, How:

" 程序員可以被分為兩種:

  1. 先確認前條件/不變式/終止條件/邊界條件,然後寫出正確的代碼
  2. 先編寫代碼,然後通過各種用例/測試/調試對程序進行調整,最後得到似乎正確的代碼

我個人保守估計前者開發效率至少是後者的 10 倍,因為前者不需要浪費大量時間在 編碼-調試-編碼 這個極其耗時的循環上。"

寫代碼之前先通過循環不變式(可以參考演算法導論中各種運用不變式證明演算法正確性的例子)確認和證明你的邏輯是沒有問題,並用邊界case確認一下具體處理的邏輯。


說一下我個人理解的刷題步驟,有助於做到bug free:

1.讀懂題意

2.抽象模型(將題目的抽象定義從題目背景中剝離)

3.根據抽象題意特徵,尋找可以解決該問題的演算法數據結構(其實演算法就那麼幾種)

4.從可能的演算法和數據結構中,反向檢驗能否解決該問題

5.從最基本的的基礎演算法開始設計

6.分析演算法複雜度,嘗試降低複雜度

7.降低複雜度的兩大途徑:

1)選擇更好的設計方法,直接改變演算法步驟

2)找出演算法步驟中的瓶頸,嘗試用數據結構優化演算法瓶頸

8.反覆迭代6-7步


我認為有幾個可行的做法:

- 用白板或者文本編輯器(不要有語法高亮和任何提示,推薦 collabedit: online text editor, 很多公司電話面用這個網站)做題。做完以後放到 IDE 裡面跑一下。如果出錯了,先自己人腦 debug. 總結錯誤。

- 自己總結各種 corner cases. 比如一個 string,就容易想到 是否 null, 是否 empty, 長度是否有限制,是否可以包含特殊字元等等。這樣下回一碰到總結過的,立即可以反應出來。

- 對一些 online judge,如果可以看到它的 test cases,留心多看看。

- 有答主說 test driven, 這很好,了解一下

- 自己嘗試一下 test framework。比如 java, 試一試 junit, 寫完代碼後自己鑽牛角給自己寫 unit tests. 培養自己從 test 角度思考的方法。

- 看一些講述 best practices 的書或者文章

另外,一個面試的經驗:做題前跟面試官快速確認各種邊界條件。做完題之後,先快速過一遍自己的代碼,如果確認沒問題而且有充足的時間,跟面試官說:我們來過幾個 test cases, 確定這個代碼是 work 的。這樣做有兩個好處:1,如果代碼有問題,你也許會自己找出來,2,給面試官留個好印象,「這小子竟然自己主動要求寫 test!」


班門弄斧一個。

念書的時候你會發現,雖然數學成績和物理成績相關性很大,但就是有些人數學好一些,物理不拔尖,或者物理好一些,數學不拔尖。我屬於後者,或者說所有學科里只有數學不好,班主任為了能讓我數學成績提高沖一衝名校,還把班裡數學最好的女生調過來跟我做同桌。慢慢交流中能發現思維的不同,拿到一道題,我腦子裡先會有一個特別的場景,然後從答案回溯到所需條件,整個是鏈狀思維。但是數學好的人拿到題能夠先發散,樹狀思維,分類討論是牢牢印在腦子裡的。

這跟刷題有點相似,記得我去年中刷第一道medium的時候,debug了整整一個小時,每次提交都能看到不過的case,然後調試代碼讓這個case通過,結果又發現有新的case不過,調到最後想砸電腦。直到後來接觸到了Partition Testing,好像一下子開了竅,好幾次競賽medium新題都能bug free一遍過,雖然水平不濟,但在bug free這一點做的還行。Partition Testing有個思維是將test case交叉分類考慮,例如需要輸入 A,B兩個Integer,那麼在無限多可能的輸入中,需要考慮A是負最大,負最大到0,0,0到正最大,正最大等,然後交叉考慮B的情況,這裡就產生了25種可能性,對稱性可以略過一些,顯然過的可以略過一些,剩下的corner case,腦跑一下代碼。

雖然這個思路在做OA和contest的時候好用,但在面試中,我發現還是很難冷靜地按這個思路來,所以多背多練,多看面經還是上策。


去Top Coder玩一陣子就能無師自通了。


我大概剛開刷時候也有跟樓主一樣的想法,最後搞煩了就把題目背下來,有空就隨便找張白紙開始寫代碼,先寫偽代碼,然後想邊際條件,然後debug一遍代碼又開始想test cases,想很多很久,導致後來刷leetcode開始吐槽他們test case不全面,然後又改一遍代碼保證結果無誤,然後上OJ再憑思路把解法打上去,不看紙啊。這還不是結束,等過了OJ再回頭在紙上重構代碼,減少不必要的代碼。最後再去OJ過一遍代碼。嗯,常被小本子寫寫畫畫比直接刷題要收穫大一些。

比如下面是某道Hard題的草稿

然後下面是重構之後的代碼

基本上就是bugfree了


刷 leetcode ,肉眼 debug 。

然後就習慣敲代碼的時候腦迴路試運行了。。

其實靠調試找 bug 是個很爛的方法,因為你不能保證運行/測試的時候能測出所有 bug 。


試試用函數式的語言,這些邊界如果不能自動處理還需要手動干預的,一定是演算法不夠好。


瀉藥 個人認為刷題足以解決你的問題 題量只要刷上去了 這些東西寫代碼的時候自然都可以預料到並提前想好怎麼解決(比如先定個小目標……刷200個題先(用心做的話,半年就可以刷到這個數字


可能需要兩方面,一方面是足夠的姿勢水平,另一方面是嚴謹的思維習慣。

姿勢水平可以告訴你這一個語句內部確切會發生什麼影響, 如何運行。也就是準確的後果預估。

思維習慣我個人感覺性格影響更大,有的人就喜歡鑽牛角尖,把每一個分支、可能性都習慣性考慮一下,有的人就馬馬虎虎,覺得八九不離十,差不多行了。我也不知道怎麼調整性格。

假如沒有那種思維習慣,多寫代碼多跳坑,坑多了經驗也會讓你記住一些不犯錯的方法,這比更改性格要容易得多。


說白了,比如for循環string什麼的,這邊界你寫代碼的時候,是自己仔細想過了,甚至找一些test case帶進去試過了,還是就心裡想著好像是這樣的,跑了/交了再說…

是後者的話就改改做題/寫代碼習慣吧,不然去面試啥用沒有,以後寫代碼也是給自己瘋狂挖坑。


一直做題一直做題做到一看到類似的題型和字眼就條件反射的下筆你就成了


先想再做,演算法是想通的,不是調試出來的,沒想通就下手,bug bug bug .....


noip2017 d1t2 和豬國殺這種題多做幾道就好了

不說了 t2爆零

哎。。。


我不是大神,寫的最長的程序也只有800多行。

所有的程序我都力求一次過,做題前算好空間複雜度,數組往大開,設置斷點查這個高深的技巧我也很想學呀,在學弟面前裝裝逼也好呀,但是事實上大部分時候都是這麼測試的

//cout&<&<""汪哥最帥""&<&代碼錯誤不可怕,邏輯錯誤才是真的爆炸


看A Discipline of Programming。

翻譯版叫編程的修鍊,翻譯的一般不過勉強能看。

看elements of programming 翻譯版叫編程原本。


語法錯誤和對語言的熟悉度是相關的。一門語言用多了自然就很少會犯語法上的錯誤。

邏輯錯誤的話也是要靠一部分經驗積累的。比如對一維dp和二維dp的判斷,backtracking的各種模板。慢慢的,腦中就會有寄存器來跟蹤各個變數的各種可能的值。這樣程序運行到什麼狀態心裡就有個數,再加上長時間的訓練產生本能的除bug能力,自然就可以避免很多邏輯錯誤了。


不太懂具體問題。

感覺是確定性的問題,循環邊界和數組下標,有時我也要花一些時間才能確定下來,但不至於交了一次才發現錯誤。

要是有不確定性、有出錯的可能性,在寫的時候是可以看出來的。確定下來只有這一種可能,而不是感覺這樣寫好像對,就不會錯。


  謝邀。

  @夏菠

  連問題都看不懂的帶我一個。。。

  程序盲淚眼爬過……

  只能給題主四個字:熟能生巧。


推薦閱讀:

如何反駁 你沒有XXXX過,沒資格評論XXXX?
如何鍛煉自己的大腦?
「田忌賽馬」的戰略可以用博弈論解釋嗎?
列數男女在思維上的差異?
怎樣將碎片化的知識進行有效的梳理?

TAG:演算法 | 程序員面試 | 思維方式 | Leetcode | 刷題 |