最近,在波利亞gg的諄諄教誨下,在pongba同學的循循善誘下,在toplanguage的今天我們思考系列的 熱情引導下,我終於痛下決心開始琢磨所謂的科學思考問題的方法。對大部分人而言,解題不是終極目的,只是希望在解題中培養的思考問題的方式能夠廣泛的應用 到其他領域。我依然覺得,思維這個抽象的可怕的東西,本質上還是個體化的,要因人而異,很難找到一招鮮吃遍天的套路。但其中,一些共性的東西還是可以抽取 出來,一起琢磨一起討論一起研究,並規範化科學化。大師的書pangbo的文章和大家的討論提供了足夠的參考素材,在這裡我只是寫我自己這些日子來的一些 實踐和思考。我混了20多年,還是乙個解題白痴,可以想見,這段日子的集訓也不會有質變的效果,所以寫下乙個beta,作為不成熟的擋箭牌。在今後的日子 裡,我會繼續的思考和實踐,希望有一天,我可以有勇氣在後面加個v1.0。。。
我一直以為,要想解決問題,除了所謂耐心勇氣等人性方面的因素外,至少還需要兩方面的儲備。一面謂之硬體,指的是基本的知識。比如說你要設計乙個演算法,基 本的複雜度分析,分治法,二分法之類的知識應該需要儲備起來;如果你要設計個軟體架構,基本的模式,作業系統的原理,互動介面的設計也應該了解一些。不要 以為自需要很小的一點知識庫,就可以像原子彈似的衍生出無限的能量,自己造輪子做汽車的生產方式,已被這個高效的社會淘汰了。牛頓gg很早就教育我們要站 在巨人的肩膀上才能站的高看得遠,而如《費馬大定理》中描繪的一樣,懷爾斯如果不是充分了解所有前人的思路深刻掌握許多高精尖的數學方法的話,從最原始的公理開始,我想再送他100年壽命估計也搞不定費馬大定理。所以,乙個人只有擁有了足夠豐富的知識後,才有可能混得和機器貓的口袋似的,要啥有啥。。。
另一面謂之軟體,指的就是解決問題的基本思維。在《why programs fail》中我了解到, 除錯這種貌似依靠經驗和靈感的活也是可以有章可循的。與之類似,所有貌似只能靠靈感噴湧來搞定的問題,也不會是只有咣噹咣噹拍腦袋才能獲得解決思路的。我 們需要信賴靈感,但很多時候,也可以不依靠靈感。我們有了足夠的知識儲備和運用知識的經驗後,就像騎上了匹寶馬良駒,有了一馬平川奔向目的地的能力,但是 沒有良好的駕馭,南轅北轍了,就算是汗血寶馬估計也無奈了。。。
從這段時間的實踐來看,波利亞gg的解題框架是極具推廣性的。不但在解題上會有效果,嘗試推廣到軟體設計甚至其他方面上,也是可以行得通的。主要實踐原料的**,除了toplanguage裡面的一些題目外,還有來自《程式設計之美》的習題和高大爺仙書上的一些經典演算法。在我這裡,波利亞gg的框架被我抽取成下述樣子,不過強烈建議自己去閱讀原著,抽取屬於自己的框架:
1. 首先是條件的提取
。對於題目而言,就是把題設的條件一部分一部分抽取出來,然後牢牢把握住未知量,從始到終,同時,要對已有已知量是否能匯出未知量有個評 估。對於其他問題而言,比如軟體設計,條件就是做這個專案的一些要求和約束,未知量就是需要做到的效果,評估就是在這樣的條件下能不能做到需要的效果。這 個問題說起來簡單,把握起來卻不容易。我在自己做題或者給別人出題的時候,我經常會發現,在做的過程中很多條件被遺忘了,或者沒有被充分利用到。 pangba的乙個實踐方法很好,就是把所有的條件都一條條寫下來,並盡可能的擴充套件開,畢竟,不是每個人都是尤拉。乙個例子,可以看這裡。。。
2. 然後是尋找解決方案。從小到大數學考試,我從來都是做完了就算,很公平,也被無數次懲罰了。驗證可以是不完備的,用基本的邏輯和特例來驗證一下,也可以是完 備的,用數學方法來證明。說這個就想起測試,寫**的時候,很多自以為完美無缺的邏輯,在測試下都顯得脆弱不堪,所以無論如何,驗證是必需的,這個懶,在 任何時候,還是不偷的好。。。
4. 擴充套件。前面說的都很簡單,客觀原因大牛們已經寫了很多了,主觀原因我很懶。因此,這一點決定多寫一點,理由是感觸多些。擴充套件,在我的定義下,有兩層意思, 乙個是對原有方法的改進,另乙個是嘗試挖掘一下為可能的問題做準備。兩者在實踐上是一致的,因此歸為一點。當你完成並驗證了某個題或某件事,你還需要進一 步的反思和改進,這就是我所謂的擴充套件,實踐包括以下幾個步驟:
4.a. 列出所有你解決方案中用到的條件。這個條件和題設的條件可能是不一致的,因為你在具體解決過程中可能加入了有形或無形的約束。比如,列印乙個樹的前序遍 歷。很有可能,你在解決這個問題的時候預設這個樹是以最常見的左右鍊錶的形式儲存的,這個過程中,你就多新增了乙個約束,有沒有想過,如果你用穿線樹的格 式存,解決方案就完全不一樣了。這樣的條件列舉還是蠻不容易的事情,很多隱藏的條件(約束)不容易被挖掘出來,要努力的多想盡量的多列。比如做比較排序的 時候,你有沒有發現,你可能新增了乙個無形的約束,就是每次都是鍵和鍵直接比較,想一想,去除掉這個約束視野會更開闊的。
4.b. 問自己一些問題,仔細思考你現行的解決方案中有沒有做重複或多餘或疑似複雜了的步驟。比如,kmp演算法就是在降低一般演算法的重複;再比如一題,找乙個n位 二進位制中的1的數目,如果你寫了乙個o(n)的演算法,仔細想想你做了什麼多餘的工作呢;還比如,冒泡演算法作為一種交換的排序演算法,有沒有做什麼疑似複雜的 操作呢。
4.c. 如果有重複步驟,嘗試在原有條件不變的前提下,優化解決方案。比如,上面所提,找1數目的題目,你可以想到既然是找1的數目,那麼應該能做到o(m)的算 法,其中m是1的個數。再繼續,能不能夠用一些其他策略,比如時間換空間,把演算法複雜度降到常數級別呢。想知道答案,可以檢視一下《程式設計之美》,呵呵。
4.d. 如果在原有條件上沒有繼續優化的空間,那麼試圖改變一些條件試試。這個條件如果是你在設計執行方案的時候新增進去的,那麼這就是乙個對已有的優化;如果,這個條件是題設的,那麼就是對這個未知的擴充套件嘗試。
4.e. 在改進的過程中,你可能引入了新的約束,更新約束列表,繼續嘗試上述步驟。
最後,寫個例子,我嘗試按照這個思路把高大爺仙書第三卷的插入排序部分串了一下,本書的其他部分我也實踐了一下,但還沒有完全一體化,如果有興趣不妨嘗試一下^_^。
a.
根據打撲克牌得來的心得,設計了乙個基於順序陣列存放的最最普通的插入排序,經驗證正確,至此,上述1~3步的工作完成。
b.提取了一下約束,包括:儲存空間是連續的靜態分配的;在排序的過程中,陣列的前半部分是有序的;每次插入乙個新元素的時候,並不能保證一定把這個元素插入到了最終位置;是基於鍵值比較來確定大小關係的;沒有使用過多的額外空間。
c.問自己乙個問題,能不能提高插入的速度?很自然我們想到了二分,於是有了二分插入。
d.再繼續,發現在目前條件下沒有太大改進空間(別說用斐波納契分...),於是考慮改變一些條件。最簡單的,如果我不保證前半部分有序,我能怎麼做。於是有了二路插入,將點定在中間,減少移動次數。
e.如果你和shell一樣有更多的硬體儲備(前面提到的,有時候是需要硬體儲備的...),你會聯想到去掉前半部分有序,可以運用區域性化和分治的思想,於是就有了shell排序。
f.如果,你開始問自己的問題是,能不能減少資料移動提高速度?乙個答案是,改變的順序儲存,變鍊錶,於是有了鍊錶插入。
g.能不能更快?於是,在原有基礎上改變,我們新增乙個哨兵指標,放在上次插入的位置。
h.不要忘了,更新一下列表,我們發現新增了乙個鏈式儲存的約束,這個約束下,二分不能使用,查詢速度降低。
i.自然而然,我們問自己,能不能查詢又快又少移動呢?繼續改變條件,還是變資料結構,於是有了樹插入(又見硬體儲備...)。
j.想想,還有沒有什麼條件沒有改變過。很顯然,基於鍵的比較沒變過,不能保證將元素插入到最終的位置也是乙個。聯想起來,能不能不基於比較基於計算,能不能盡量一次到位這樣可以減少移動次數。如果足夠幸運,你可以想出基於位址的排序。
k.其實,還有很多條件沒有變過或可以繼續變,有興趣就繼續下去吧:)。。。
解決問題的思路beta
size large 1.首先是條件的提取 2.然後是尋找解決方案 3.做完了一定要驗證 4.擴充套件 a.列出所有你解決方案中用到的條件 b.問自己一些問題,仔細思考你現行的解決方案中有沒有做重複或多餘或疑似複雜了的步驟 c.如果有重複步驟,嘗試在原有條件不變的前提下,優化解決方 size 最近,...
解決問題的思路beta
最近,在波利亞gg的諄諄教誨下,在pongba同學的循循善誘下,在toplanguage的今天我們思考系列的熱情引導下,我終於痛下決心開始琢磨所謂的科學思考問題的方法。對大部分人而言,解題不是終極目的,只是希望在解題中培養的思考問題的方式能夠廣泛的應用到其他領域。我依然覺得,思維這個抽象的可怕的東西...
解決問題的思路
乙個if else 體現出的解決問題的能力,思路,這就是錢 string tostation string jobj data i agv target place code string mocode string jobj data i mo code 工單 task.receive date ...