很多問題並不完全符合二分的模型。最常見的乙個情況估計應該是無窮長的有序佇列中的二分查詢問題。例如,前文所提到的求解x^x=a實際上就是這樣的問題,這裡x的取值範圍可以是大於0的所有實數。當然,這裡的x明顯有乙個上界,比如x明顯要比a小。但是,如果有什麼二分問題,它沒有乙個明確的上界呢?比如,我們再玩一次猜數遊戲,我想乙個數,然後告訴你你的猜測是大了還是小了。不同的是,我不告訴你這個數是在什麼範圍內選的,我想的數可以是任意乙個正整數。那你該怎麼辦呢?最初的想法當然是,不斷往大的猜,直到某個時候它超過了目標值為止;然後以它為上界,剩下的就可以看作有限多了。關鍵是,我們以什麼樣的跨度來列舉這個上界?首先必須肯定的是,這個上界列舉序列必須是發散的,否則會有數我們一輩子也猜不到;同時,線性增長的策略也是很傻的:跨度太小了你可能得到猴年才能找出上界,跨度太大了的話一來就確定了上界,但待考慮的佇列也可能遠遠超過所需。乙個比較靈活的想法是:按照1, 2, 4, 8, 16, ..., 2^n的序列來猜測上界。這是一種「相對大小」的思想:既然連前面n個數都小了,我們也就不在乎那麼一兩個了,不妨直接再跳過n個數直接考察2n。這樣的話,整個猜測過程仍然保持log(n)的複雜度,整個演算法也更加美觀一些。
假如你有一台時光機,可以讓你到任意遠的未來去,你打算怎麼來使用它?或許你會說,先去100年後看看,生活一年之後再去200年後體驗體驗,然後再去300年後生活一年,再去400年後生活一年……其實,這種線性的時光旅行並不科學。當你已經跨越了數千年以後,相比之下100年的跨度已經不算遙遠了,2023年後與2023年後的差異遠遠沒有今天和100年以後的變化那樣令人震撼。我說我和stetson mm的思維如出一轍,那不是說著好玩的。一次msn聊天時我們討論到這個話題,兩人同時想到了這樣的時間旅行方式:先直接跳到1年後生活,再到2年後生活一段時間,再到4年後,再到8年後……用這種方式來體驗未來,即使我在每乙個時間點停留一年,我也能保證見到從我餘生的感情生活到人類文明的各種不可思議的形態,甚至到文明的輪迴與宇宙的毀滅等各種尺度下的牛b事。我的確能夠看到充分遠的未來,了解到足夠巨集大的文明史和宇宙史:假設我還能活80年,那麼我可以看到2^80=1208925819614629174702023年內的種種,這麼多年裡估計就是宇宙熱寂也該結束了。
摺紙後的高度、在棋盤裡放公尺、hanoi塔與世界末日……無數火星的例子告訴我們,倍增的力量是異常強大的。如果你不信的話,下次來北京時請我喝酒,不妨這樣來試試:先我喝一杯,你喝一口;然後我喝一杯,你喝兩口;然後我喝一杯,你喝四口……看咱倆誰堅持的久。
倍增法有許多出乎意料的神奇應用。有興趣的讀者不妨去看一看chan凸包演算法,這是我所見過的倍增法最詭異的應用。
問題的關鍵就是,每一次我們的x和y取在**最合適?或許有人會說,既然有兩個點,那就對稱地取在三等分處吧。這樣的話,每次問題的規模都降低到原來的2/3。當然,更好的辦法是把兩個點都取到中點附近,相互之間的距離充分小;這雖然不那麼美觀,但每次的規模都將變為原先的1/2+ε,效率上說顯然更好一些。最聰明的做法是,把x和y兩點取在一對既不遠也不近的合適位置上,使得其中乙個點(比如y)被去掉後,x點所在的位置正好可以作為下乙個測試點(於是每一輪新的實驗就只需要取乙個點了)。這種「迴圈利用」舊測試點的做法將更加節省資源。為了保證這一過程可以永遠進行下去,我們希望讓x在y點去掉後的那一段上的位置與y點原先在整段上所處的位置比例相同,用算式寫出來就是y/l=x/y,即(l-x)/l = x/(l-x),解出來x=(1±√5)l/2。神奇!**分割竟然出現在了這樣乙個意想不到的場合中!這就是所謂的「優選法」:不斷在兩個**分割點處進行測試,拋棄較次的測試點;由於**分割點的性質,另乙個點仍然處於餘下部分的**比例處,因此只需再對該小段的另一**分割點進行測試即可繼續如此遞迴地操作下去。
二分的應用範圍還很廣。這裡我們再舉四個簡單的例子,它們是二分法的各種極其特殊的用法。首先,我們來看看互動式問答題中的乙個奇妙的二分。黑箱子中有乙個競賽圖(任兩點之間都有一條單向邊)。詢問兩個頂點,返回它們之間的邊的方向。請用盡量少的詢問次數找出一條經過全部n個頂點的路徑。
競賽圖有乙個神奇的性質:經過所有頂點的路是一定存在的。換句話說,如果n個人之間兩兩進行比賽,假設比賽沒有平局;那麼我們一定能夠給這n個人排出乙個順序,使得第乙個人打敗了第二個人,第二個人打敗了第三個人,一直到倒數第二個人打敗了最末乙個人。這個證明是構造性的。從任意一條邊出發,我們可以不斷擴充套件出越來越長的鏈。假設現在我們已經有了乙個長度為k的鏈,它們的節點分別是p_0, p_1, ..., p_k。現在我們想把節點p_t加進來,使得這條鏈的長度達到k+1。注意到,如果有邊p_t → p_0或者p_k → p_t,那就直接完事兒了。否則的話,我們必須要找出鏈中的乙個p_i,使得p_i → p_t並且p_t → p_(i+1),然後將p_t插到p_i和p_(i+1)中間。這樣的p_i是一定存在的,因為此時p_0到p_t的邊是正向的,但到了p_k時從鏈到p_t的邊卻變成逆向的了,這說明中間至少有從正向邊變成逆向邊這一步。換句話說,給你乙個長度為k的01串,首位為0,末尾為1,那中間至少出現了一次子串「01」。
按照這種方法做,最壞情況下我們需要詢問o(n^2)條邊。這相當於把整個圖都給你了。有更好的辦法嗎?有!我們可以用二分法尋找p_i,從而只需要o(nlogn)次詢問即可得到答案。具體地說,每次需要尋找那個p_i時,我們二分p_i的位置:如果有p_i→p_t,則p_t一定能插入到p_i後面的部分;反之如果p_t→p_i,則需要尋找的目標節點一定在它前面。用01串來解釋似乎更清楚一些:由於每個首位為0末位為1的子串都包含至少乙個「01」,於是我們看中間那一位數。如果它是「0」,即可拋棄前面那一段;如果它是「1」,則後面那一段就可以不管它了。
接下來,讓我們看一看二分法在兩個有序陣列中的應用。在多個有序陣列中查詢指定的數不好玩,真正好玩的是在多個有序陣列中查詢指定序數的數。給你兩個有序陣列,如何快速找出第k小的數?合併兩個有序陣列將導致線性的複雜度,這裡還有更好的演算法嗎?不囉嗦了,我直接給出答案:分別取兩個陣列正中間的那個數a和b,不妨設a≥b。兩個陣列被劃分為四段,分別記作a1、a2、b1和b2。如果a1的長度與b1的長度加起來還沒有k大,那所求數絕對不可能在b1裡面(任選b1中的乙個數,比它小的只有a1和b1各自的一部分數,數目遠不到k);反之如果len(a1)+len(b1)≥k,那麼所求元素必然不在a2中(因為a1和b1裡的所有數都比a2裡的數小,而它們就已經有k個了)。對於兩種情況,我們都可以將某個陣列的長度減半,從而得到log級別的演算法。
1 2 3 6 7 8 14 *16* 18 19 20 23 27 28 33
|| a ||
4 5 9 10 11 *12* 14 17 22 24 29
|| b ||
在競賽題目中,大家見過最多的當屬二分加貪心檢測了。當然,偶爾也會遇到二分加最短路、二分加匹配、二分加網路流、二分加動態規劃之類的題目。但是,大家有想過二分加二分的題目嗎?前不久,我就見過這麼一道「兩次二分」的題目:給你n個數,這n個數兩兩的差值將產生n(n-1)/2個數。試求這n(n-1)/2個數的中位數。演算法:二分答案加二分檢測。先二分這個中位數,然後數一數比該數小的有多少,比該數大的又有多少,以確定這個「中位數」是取大了還是取小了。為了判斷有多少個數比選定的中位數小,我們需要再一次使用二分:對於每乙個固定的數a_i,二分a_j的位置,看a_i-a_j比中位數大還是小(j=1..i-1,假設數列已經有序)。假設n個數中的最大值為q,則演算法的複雜度為o(n*log(n)*log(q))。
有時候,二分的作用甚至根本就不是為了減小時間複雜度。某天在閱微堂看到乙個非常有趣的題目。假設有兩台計算機,每台計算機上都存了乙個長度為n的字串。兩台計算機之間的資料傳輸是非常昂貴的。因此,我們希望用最少的資料傳輸量來確定,哪台計算機上儲存的字串的字典序更大。
答案:乙個基於概率的二分演算法。兩台機器各自算出前半段字串的md5值,然後機器a把它的md5值傳過來和機器b比。把比較結果傳回去。若兩個md5值不等,表明第乙個不同之處一定在這裡面發生,此時即可拋棄後面一半;若兩個md5值相等則說明不同的地方一定在後面,前面這一半即可捨去。(補充一句,這裡的「一定」並不是真的一定,md5判重是有概率因素的。)
漫話二分(上)
如果真的叫乙個課講的好的老師來說二分,課程可以變得相當有意思。每次回我們高中時我都講了很多次課,我最喜歡聊到的話題之一就是二分。從猜數遊戲引入二分查詢有序佇列中的指定元素,然後提出一些標準的有序佇列二分搜尋的實際應用,比如解方程x x 100一類的問題。緊接著提出二分的各種有趣的變形,例如如何在有序...
1026 二分查詢(下)
目錄 一 四種常見的二分查詢變形問題 二 實現 三 適用性分析 四 思考 1.查詢第乙個值等於給定值的元素 2.查詢最後乙個值等於給定值的元素 3.查詢第乙個大於等於給定值的元素 4.查詢最後乙個小於等於給定值的元素 前提假設 以資料是從小到大排列為前提來實現 1.查詢第乙個值等於給定值的元素,比如...
總結 二分查詢(下)
總結 二分查詢 下 一 四種常見的二分查詢變形問題 16 二分查詢 下 如何快速定位ip對應的省份位址?file j geektime 唯一更新qq群170701297 ebook 資料結構與演算法之美 16二分查詢 下 如何快速定位ip對應的省份位址?html 2019 2 17 17 27 19...