周三下午的算法面試間里,主面試官把白板筆遞給小張,畫(huà)出兩個(gè)簡(jiǎn)單的數(shù)字:n=3, m=27。題目很直白——不求調(diào)用任何數(shù)學(xué)庫(kù),只靠最基礎(chǔ)的代碼,找出整數(shù)x,使得x的3次方剛好等于27,若不存在就返回-1。這道題有個(gè)更通用的名字:求解一個(gè)數(shù)的N次方根。它隱藏著一個(gè)在程序員群體中爭(zhēng)論不休的話題:面對(duì)這樣的問(wèn)題,究竟該從暴力搜索開(kāi)始,還是直接亮出二分查找?
正方觀點(diǎn)總認(rèn)為,暴力法就是最可靠的底線。小張?jiān)诮忉寱r(shí)列出思路:“從1一直試到m,每個(gè)數(shù)字都計(jì)算它的n次方,只要某個(gè)數(shù)的n次方與m相等,就找到答案了。”這段敘述完全符合直覺(jué)——既然x必定落在1到m之間,按順序逐個(gè)驗(yàn)證,總能捕獲任何可能的結(jié)果。但反方立刻就能從復(fù)雜度報(bào)表里嗅到問(wèn)題:暴力法做一次驗(yàn)證就需要乘n次,如果m很大,計(jì)算量輕松膨脹到 O(m×n)。比方說(shuō),當(dāng)m取到億級(jí)、n為兩位數(shù)時(shí),即便單次乘法再快,整體耗時(shí)也會(huì)讓人失去耐心。而這還只是時(shí)間開(kāi)銷(xiāo),反方更在意的是——有多少計(jì)算其實(shí)根本沒(méi)必要?
![]()
冷靜審視暴力法的每一輪操作,會(huì)發(fā)現(xiàn)它缺失一種判斷力:當(dāng)中間某個(gè)數(shù)字的n次方已經(jīng)遠(yuǎn)大于m,后續(xù)所有更大的數(shù)字只會(huì)產(chǎn)生更大的冪值,再繼續(xù)嘗試就是在浪費(fèi)算力。這就把爭(zhēng)論推到一個(gè)決定性的事實(shí)上——冪函數(shù) f(x)=x? 在正數(shù)范圍內(nèi)是嚴(yán)格單調(diào)遞增的。一旦確認(rèn)單調(diào)性,反方最鋒利的武器就可以登場(chǎng):既然x越大,x?也越大,那么當(dāng)我們測(cè)算某個(gè)中間值mid的n次方時(shí),就能立即決定答案該往左走還是往右走。如果mid?正好等于m,游戲結(jié)束;如果mid?小于m,所有比mid小的值都不必再看;如果大于m,所有比mid大的值直接整片丟棄。這種每次砍掉一半搜索空間的動(dòng)作,恰好是二分查找的靈魂,只不過(guò)這里查找的不是數(shù)組的索引,而是答案本身。
把二分查找搬上答案空間,在剛接觸時(shí)很容易讓人遲疑:二分查找不是只適用于有序數(shù)組嗎?數(shù)組的排序感從哪里來(lái)?其實(shí)排序感恰恰來(lái)自單調(diào)遞增函數(shù)。小張?jiān)诎装迳袭?huà)出一個(gè)虛擬的搜索區(qū)間 [1, m],取中點(diǎn)mid=14,計(jì)算14的3次方,得到2744——這遠(yuǎn)大于目標(biāo)27。于是他毫不猶豫地把區(qū)間收縮到 [1,13]。再取中點(diǎn)7,7的3次方343仍然大于27,區(qū)間繼續(xù)左移,變成 [1,6]。第三次取中點(diǎn)3,3的3次方恰好為27,答案找到。整個(gè)過(guò)程中,每一步淘汰掉的候選值數(shù)量都接近剩余總量的一半,最終只需要在大約 log?(m) 輪內(nèi)就能逼近結(jié)果。計(jì)算一次mid?的代價(jià)是 O(n),總時(shí)間復(fù)雜度被穩(wěn)穩(wěn)壓縮到 O(n log m),空間復(fù)雜度保持 O(1)。這種成本結(jié)構(gòu)讓反方觀點(diǎn)得到硬數(shù)據(jù)支撐:在m足夠大時(shí),二分搜索比暴力法節(jié)省的時(shí)間不只是幾倍,而是指數(shù)級(jí)的差異。
但是,正方也有一個(gè)容易被忽視的務(wù)實(shí)提醒:當(dāng)n很小或m本身就非常小時(shí),暴力法未必就輸。比如 n=2, m=9,暴力從1試到9,只比二分多驗(yàn)證幾輪,代碼還要更簡(jiǎn)單,出錯(cuò)的幾率也更低。反方通常會(huì)用“可伸縮性”來(lái)回應(yīng)——處理實(shí)際系統(tǒng)中的不確定規(guī)模時(shí),我們無(wú)法假設(shè)m一定友好。一旦數(shù)據(jù)量膨脹,暴力的 O(m×n) 馬上就會(huì)撞上性能天花板,而二分的對(duì)數(shù)復(fù)雜度能從容應(yīng)對(duì)。由此,我判斷,面試中真正值得記住的不是選擇哪一種解法,而是識(shí)別出“答案落在某個(gè)連續(xù)區(qū)間、且存在單調(diào)判定條件”的模式。只要嗅到這個(gè)味道,二分搜索答案就能把看似需要逐一遍歷的問(wèn)題轉(zhuǎn)變成快速剪枝的優(yōu)化問(wèn)題。
小張最后的總結(jié)非常精煉,也成為這個(gè)模式的一句從業(yè)者口訣:“mid? 比 m 小就往右走,比 m 大就往左走,相等就返回。”記住這條記憶鉤子,就能在遇到“平方根、N次方根、Koko吃香蕉的最小時(shí)速、運(yùn)送包裹的最小容量、制造花束的最少天數(shù),甚至憤怒的奶牛”等同類題目時(shí),第一時(shí)間調(diào)出二分答案的庫(kù)。這些表面不同的問(wèn)題共享同一個(gè)內(nèi)核:我們都在一個(gè)可能有幾百萬(wàn)甚至幾十億候選值的范圍里,尋找一個(gè)恰好滿足單調(diào)約束的標(biāo)桿。暴力從頭走到尾的思維方式固然穩(wěn)妥,但在搜索空間前加上二分,就相當(dāng)于給代碼裝上了一個(gè)精準(zhǔn)的方向盤(pán),讓每一步操作都帶著信息而非盲目遍歷。
這場(chǎng)辯論的本質(zhì),并不是在貶低暴力法的存在價(jià)值,而是在提醒開(kāi)發(fā)者:面對(duì)一個(gè)看似只靠“練”才能提效的搜索問(wèn)題時(shí),冷靜拆解其單調(diào)性,往往能找到對(duì)數(shù)級(jí)的捷徑。下次當(dāng)你站在白板前,被要求手算一個(gè)數(shù)的立方根或判定某個(gè)吞吐量閾值時(shí),不妨先問(wèn)問(wèn)自己:答案是否落在一個(gè)單調(diào)的世界里?如果是,二分就是你最冷靜也最鋒利的那把刀。
特別聲明:以上內(nèi)容(如有圖片或視頻亦包括在內(nèi))為自媒體平臺(tái)“網(wǎng)易號(hào)”用戶上傳并發(fā)布,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.