說一說程式設計師“舉一反三”的能力
獲得思想的能力,我們稱之為智力。解決一個問題,如果你能做到舉一反三,那麼你就真正獲得瞭解決這一類問題的思想了。
好吧,我們一起來體會一下自己“舉一反三”的能力究竟怎麼樣。
題圖:“私想者”
一、從快速排序說起
快速排序可以說是應用最廣的一種排序演算法。其思想是基於分治模式,將問題不斷縮小,對小的問題進行排序,合併,後最終完成排序。
其中,快速排序最為核心的一個步驟是劃分(partition)待排序陣列:從陣列中選擇一個元素(主元),然後以這個主元為基準,將陣列劃分成兩部分,使得前邊部分元素都小於主元,後邊部分元素都大於主元。(這裡假設為從小到大排序),更詳細的快速排序介紹見此文:快速排序
如下圖所示為一個劃分陣列的例項,這裡選取陣列的最後一個元素作為主元。
其虛擬碼如下:
//核心函式,對陣列A[p,r]進行就地重排,將小於A[r]的數移到陣列前半部分,將大於A[r]的數移到陣列後半部分。 PARTITION(A,p,r) pivot <—— A[r] i <—— p-1 for j <—— p to r-1 do if A[j] < pivot i <—— i+1 exchange A[i]<——>A[j] exchange A[i+1]<——>A[r] return i+1
二、如果你理解了快速排序演算法思想
假設你知道並理解了快速排序演算法,我們接下來解決如下一個問題。
問題描述:
輸入一個整數陣列,調整陣列中數字的順序,使得所有奇數位於陣列的前半部分,所有偶數位於陣列的後半部分。要求時間複雜度為O(n)。
分析與解答:
最容易想到的辦法是從頭掃描這個陣列,每碰到一個偶數,拿出這個數字,並把位於這個數字後面的所有數字往前挪動一位。挪完之後在陣列的末尾有一個空位,然 後把該偶數放入這個空位。由於每碰到一個偶數,需要移動O(n)個數字,所以這種方法總的時間複雜度是O(n^2),不符合題目要求。
事實上,若把奇數看做是小的數,偶數看做是大的數,那麼按照題目所要求的奇數放在前面偶數放在後面,就相當於小數放在前面大數放在後面,聯想到快速排序中 的partition過程,不就是通過一個主元把整個陣列分成大小兩個部分麼,小於主元的小數放在前面,大於主元的大數放在後面。
而partition過程有以下兩種實現:
- 一頭一尾兩個指標往中間掃描,如果頭指標遇到的數比主元大且尾指標遇到的數比主元小,則交換頭尾指標所分別指向的數字;
- 一前一後兩個指標同時從左往右掃,如果前指標遇到的數比主元小,則後指標右移一位,然後交換各自所指向的數字。
類似這個partition過程,奇偶排序問題也可以分別借鑑partition的兩種實現解決。
為何?比如partition的實現一中,如果最終是為了讓整個序列元素從小到大排序,那麼頭指標理應指向的就是小數,而尾指標理應指向的就是大數,故當頭指標指的是大數且尾指標指的是小數的時候就不正常,此時就當交換。
因此,我們的做法是維護兩個指標i和j,一個指標指向陣列的第一個數的前一個位置,我們稱之為後指標i,向右移動;一個指標指向陣列第一個數,稱之為前指標j,也向右移動,且前指標j先向右移動。如果前指標j指向的數字是奇數,則令i指標向右移動一位,然後交換i和j指標所各自指向的數字。
如果你能很快想到類似快排partition的解決方案,說明你理解了快速排序。
三、舉一反三——是金子,你就應該發光
奇偶調序問題我們順利用partition思想在O(n)的複雜度下解決了戰鬥,恩,我們獲取思想的能力還是不錯的。接下來,我們再來一瓶:荷蘭國旗問題。
拿破崙席捲歐洲大陸之後,代表自由,平等,博愛的豎色三色旗也風靡一時。荷蘭國旗就是一面三色旗(只不過是橫向的),自上而下為紅白藍三色。
該問題本身是關於三色球排序和分類的,由荷蘭科學家Dijkstra提出。由於問題中的三色小球有序排列後正好分為三類,Dijkstra就想象成他母國的國旗,於是問題也就被命名為荷蘭旗問題(Dutch National Flag Problem)。
問題的正規描述:
有n個紅白藍三種不同顏色的小球,亂序排列在一起,請通過兩兩交換任意兩個球,使得從左至右,依次是一些紅球、一些白球、一些藍球。
分析與解法:
首先,你看到在問題,可能會無從下手。但如果給你提示,讓你儘量往快排思想上靠攏呢?
我們知道,快速排序依託於一個partition分治過程,在每一趟排序的過程中,選取的主元都會把整個陣列排列成一大一小的部分,那我們是否可以借鑑partition過程設定三個指標完成重新排列,使得所有球排列成三個不同顏色的球呢?
由此,我們得到此問題的一個解決方法:
通過前面的分析得知,這個問題類似快排中partition過程,只是需要用到三個指標:一個前指標begin,一箇中指標current,一個後指標end,current指標遍歷整個陣列序列,當
- current指標所指元素為0時,與begin指標所指的元素交換,而後current++,begin++ ;
- current指標所指元素為1時,不做任何交換(即球不動),而後current++ ;
- current指標所指元素為2時,與end指標所指的元素交換,而後,current指標不動,end– 。
為什麼上述第3點中,current指標所指元素為2時,與end指標所指元素交換之後,current指標不能動呢?因為第三步中current指標所 指元素與end指標所指元素交換之前,如果end指標之前指的元素是0,那麼與current指標所指元素交換之後,current指標此刻所指的元素是 0,此時,current指標能動麼?不能動,因為如上述第1點所述,如果current指標所指的元素是0,還得與begin指標所指的元素交換。
說這麼多,你可能不甚明瞭,直接引用下gnuhpc的圖,就一目瞭然了:
通過以上幾個問題,你現在可以給自己“舉一反三”的能力打個分了。
如果你覺得你懂了快速排序演算法,在給出提示的情況下,卻沒能想到荷蘭國旗問題的相關解法,甚至奇偶調序問題都想不到相關的解法,你應該問問自己:你真的懂了嗎?
不管你懂不懂,我反正不懂!
全文大部分內容整理自《程式設計師程式設計藝術》一書部分章節。
相關文章
- 說一說javascript的非同步程式設計JavaScript非同步程式設計
- [黑客說]一個新的程式設計師交流平臺黑客程式設計師
- 話說C#程式設計師人手一個ORMC#程式設計師ORM
- 1024 看到程式設計師的朋友圈說說程式設計師
- 一個女程式設計師徵男友的需求說明書程式設計師
- [駭客說]一個新的程式設計師交流平臺程式設計師
- 那個程式設計師說一個輸入框要做一週程式設計師
- 程式設計師的4條說法程式設計師
- 程式設計師如何能把一個功能說的工作量很大?程式設計師
- 程式設計師不能說自己不行啊程式設計師
- 說說Vue 3.0中Treeshaking特性?舉例說明一下?Vue
- 反直覺SQL舉例說明SQL
- ios程式設計師提高程式設計能力萬無一失的辦法iOS程式設計師
- 說一說併發設計模式—Future(非同步)設計模式非同步
- 有個碼齡 10 年的程式設計師跟我說:“他程式設計從來不用滑鼠”,我說:程式設計師
- 程式設計師你應該勇敢說不程式設計師
- 程式設計師的“能力陷阱”程式設計師
- 說一下泛型原理,並舉例說明泛型
- 程式設計師最常說的9句話,精準!程式設計師
- 【轉發】為什麼說程式設計師是一個極度勞累的工作?程式設計師
- 為什麼說一個好的Java程式設計師,是無碼勝有碼?Java程式設計師
- 面試官:說一說Zookeeper中Leader選舉機制面試
- 聽說,99% 的 Go 程式設計師都被 defer 坑過Go程式設計師
- 一文說通C#中的非同步程式設計C#非同步程式設計
- 論跟程式設計師談話的技巧:千萬不要跟程式設計師說,你的程式碼有bug程式設計師
- 像程式設計師一樣思考——提高解決問題的能力程式設計師
- 程式設計師的那些反模式程式設計師模式
- 誰說程式設計師沒有520?學學高階程式設計師都是怎麼表白的……程式設計師
- 程式設計師嘛,先做個好架構師再說程式設計師架構
- 誰說程式設計師找不到女朋友,程式設計師明明那麼有市場!程式設計師
- RxPermissions 原始碼解析之舉一反三原始碼
- 為什麼說程式設計師做外包沒前途?程式設計師
- 說說一個編劇眼中“劇情設計最精妙”的遊戲遊戲
- 他可能是全球最會說唱的程式設計師程式設計師
- 舉例說明物件導向程式設計有什麼缺點?物件程式設計
- 好程式設計師Web前端分享程式的三大結構(一)程式設計師Web前端
- 重走JAVA程式設計之路(一)列舉Java程式設計
- 《說文解字》與程式設計程式設計
- 超細!細說Zookeeper選舉的一個案例(下)