算法概論筆記 - 分治法

  1. 將原問題分解為一組子問題匙瘪,每個(gè)子問題都與原問題類型相同菩彬,但是比原問題的規(guī)模小
  2. 遞歸求解這些子問題
  3. 將子問題的求解結(jié)果恰當(dāng)合并,得到原問題的解

分治算法更多地是使已經(jīng)能在多項(xiàng)式時(shí)間內(nèi)解決的問題求解得更快旨枯。

二進(jìn)制乘法

假設(shè)x和y是兩個(gè)n位二進(jìn)制整數(shù)独悴,我們將每個(gè)數(shù)都一分為二例书,每個(gè)數(shù)的左半部分和右半部分都是n/2位二進(jìn)制數(shù):

![](http://latex.codecogs.com/svg.latex?xy = (2^{n/2}x_L + x_R)(2^{n/2}y_L + y_R) = 2^nx_Ly_L + 2^{n/2}(x_Ly_R + x_Ry_L) + x_Ry_R)

此時(shí),T(n) = 4T(n/2) + O(n)刻炒,時(shí)間復(fù)雜度為O(n^2)

![](http://latex.codecogs.com/svg.latex?x_Ly_R + x_Ry_L = (x_L + x_R)(y_L + y_R) - x_Ly_L - x_Ry_R)

這時(shí)决采,T(n) <= 3T(n/2 + 1) + O(n),時(shí)間復(fù)雜度為
矩陣乘法

兩個(gè)nn的矩陣X和Y的乘積得到另一個(gè)nn的矩陣Z=XY

直接計(jì)算

時(shí)間復(fù)雜度=![](http://latex.codecogs.com/svg.latex?n^2*O(n) = O(n^3)?)

元素?cái)?shù)目*每個(gè)元素的計(jì)算時(shí)間

分治優(yōu)化

利用矩陣乘法能夠分塊進(jìn)行的特性

![](http://latex.codecogs.com/svg.latex?X =\begin{pmatrix}A & B\C & D\\end{pmatrix})

![](http://latex.codecogs.com/svg.latex?Y =\begin{pmatrix}E & F\G & H\\end{pmatrix})

從而坟奥,

![](http://latex.codecogs.com/svg.latex?XY =\begin{pmatrix}A & B\C & D\\end{pmatrix}\begin{pmatrix}E & F\G & H\\end{pmatrix}=\begin{pmatrix}AE+BG & AF+BH\CE+DG & CF+DH\\end{pmatrix}=\begin{pmatrix}P_5+P_4-P_2+P_6 & P_1+P_2\P_3+P_4 & P_1+P_5-P_3-P_7\\end{pmatrix})
其中树瞭,
![](http://latex.codecogs.com/svg.latex?\quad P_1=A(F-H)\quad P_2=(A+B)H\quad P_3=(C+D)E\quad P_4=D(G-E)\quad P_5=(A+D)(E+H)\quad P_6=(B-D)(G+H)\quad P_7=(A-C)(E+F))

算法T(n) = 7T(n/2) + O(n^2),根據(jù)主定理可得爱谁,

時(shí)間復(fù)雜度=
遞歸樹視角:

算法的遞歸調(diào)用構(gòu)成一個(gè)樹狀結(jié)構(gòu)晒喷。在深度為k的層次上,共有

個(gè)子問題访敌,每一個(gè)的規(guī)模都是
凉敲,該層次花費(fèi)的時(shí)間為
。在
的層次上寺旺,子問題的規(guī)模降為1爷抓,此時(shí)![](http://latex.codecogs.com/svg.latex?(\frac32)^{log_2n}O(n) = 3^{log_2n} = n^{log_23})

換底公式![](http://latex.codecogs.com/svg.latex?log_ab = \frac {log_cb}{log_ca})

對(duì)于二進(jìn)制乘法,通常不需要將子問題的規(guī)模降至1阻塑。對(duì)于大多數(shù)處理器而言蓝撇,16位或32位的二進(jìn)制乘法都被視為一次單獨(dú)的操作

通用模式

在解決規(guī)模為n的問題時(shí),總是先遞歸地求解a個(gè)規(guī)模為n/b的子問題陈莽,然后再

時(shí)間內(nèi)將子問題的解合并起來渤昌,其中a>0,b>1,d>=0是一些特定的整數(shù)。
此時(shí)传透,主定理:![](http://latex.codecogs.com/svg.latex?T(n) = aT(\lceil n/b \rceil) + O(n^d))
時(shí)間復(fù)雜度為
![](http://latex.codecogs.com/svg.latex?T(n) =\begin{cases}O(n^d) & if ; d > log_ba \O(n^dlogn) & if ; d = log_ba \O(n^{log_ba}) & if ; d < log_ba \\end{cases})

歸并排序

將該數(shù)的序列分為兩部分耘沼,遞歸地對(duì)每一部分進(jìn)行排序,最后將兩個(gè)有序子序列進(jìn)行合并

merge
function merge(x[1...k], y[1...l])
if k=0: return y[1...l]
if l=0: return x[1...k]
if x[1] <= y[1]:
    return x[1]+merge(x[2...k],y[1...l])
else:
    return y[1]+merge(x[1...k],y[2...l])

merge()時(shí)間復(fù)雜度為O(k+l)朱盐,即線性時(shí)間
mergesort()滿足T(n) = 2T(n/2) + O(n)群嗤,根據(jù)主定理可得時(shí)間復(fù)雜度為O(nlogn)

merge()的實(shí)現(xiàn)通常面臨兩個(gè)選擇:

  1. 線性附加內(nèi)存,花費(fèi)將數(shù)據(jù)拷貝到臨時(shí)數(shù)組再拷貝回來的附加工作
  2. 交換位置(類似插入排序)兵琳,若y半段對(duì)應(yīng)元素較小狂秘,則面臨將x半段對(duì)應(yīng)元素至x半段末尾的元素的這一子段全體右移一位的代價(jià)

做法2可能會(huì)使歸并排序退化為插入排序,因此通常選擇線性附加內(nèi)存

function merge(x[1...k], y[1...l])
init empty z[1...k+l]
xPos, yPos, zPos -> 1

while xPos <= k && yPose <= l:
    if x[xPos] <= y[yPos]:
        z[zPos++] = x[xPos++]
    else:
        z[zPos++] = y[yPos++]:

while xPos <= k
    z[zPos++] = x[xPos++]
while yPos <= l
    z[zPos++] = y[yPos++]
    
copy temp array z back

任一時(shí)刻只需要一個(gè)臨時(shí)數(shù)組躯肌,因此該臨時(shí)數(shù)組可以僅存有一個(gè)者春,merge()使用該臨時(shí)數(shù)組的任意部分

遞歸版
function mergesort(a[1...n])
Input: An array of number a[1...n]
Output: A sorted version of this array

if n > 1:
    return merge(mergesort(a[1...n/2]),
                mergesort(a[n/2+1...n]))
else:
    return a

see implement: divide.MergeSortRecur

迭代版

可以發(fā)現(xiàn),合并操作直到遞歸進(jìn)入到單元素?cái)?shù)組的層次時(shí)才真正開始清女,1->2->4->8...依次類推(類似自底向上)

function iterative-mergesort(a[1...n])
Input: elements a1, a2, ..., an to be sorted

Q = [] (an empty queue whose elment's type is array)
for i = 1 to n:
    inject(Q, [ai])
while |Q| > 1:
    inject(Q, merge(eject(Q), eject(Q)))
return eject(Q)

see implement: divide.MergeSortIter

擴(kuò)展

在Java的泛型排序(使用Comparator)中钱烟,進(jìn)行一次元素比較可能比較昂貴(因?yàn)楸容^可能不容易被內(nèi)嵌,從而動(dòng)態(tài)調(diào)度的開銷可能會(huì)減慢執(zhí)行的速度),但是移動(dòng)元素則是省時(shí)的(因?yàn)樗鼈兪且玫馁x值拴袭,而不是龐大對(duì)象的拷貝)读第。歸并算法使用所有流行的排序算法中最少的比較次數(shù),因此拥刻,它就是標(biāo)準(zhǔn)Java類庫中泛型排序所使用的的算法怜瞒。

通過兩兩元素之間的比較進(jìn)行排序,必須要執(zhí)行O(nlogn)次比較操作般哼。
原因
通過兩兩元素之間的比較進(jìn)行排序的算法可以通過樹結(jié)構(gòu)來描述吴汪,樹的每個(gè)葉節(jié)點(diǎn)都標(biāo)記一個(gè)關(guān)于原輸入元素序列的排列。從樹根節(jié)點(diǎn)到樹葉節(jié)點(diǎn)的最長路徑上的比較次數(shù)為該算法時(shí)間復(fù)雜度的最差情況蒸眠。

該二叉樹至少包含有n!個(gè)葉節(jié)點(diǎn)(排列數(shù)目)漾橙,因此這棵樹的寬度至少是

,因此最差情況下必須要執(zhí)行O(nlogn)次比較操作黔宛,即算法復(fù)雜度為O(nlogn)

選擇S中第k小元素
普通策略
  1. 排序問題:對(duì)S進(jìn)行排序近刘,返回相應(yīng)位置k的元素
  2. 取S中k個(gè)最小數(shù)的問題:將S中前k個(gè)元素讀入(某數(shù)據(jù)結(jié)構(gòu))并以遞減順序?qū)ζ溥M(jìn)行排序擒贸。接著臀晃,逐個(gè)讀入剩下的元素,若該元素大于第k個(gè)元素介劫,則忽略它徽惋;否則將其放至(某數(shù)據(jù)結(jié)構(gòu))中正確的位置,同時(shí)將第k個(gè)元素?cái)D出座韵。當(dāng)算法終止時(shí)险绘,位于第k個(gè)位置上的元素作為答案返回

其中某數(shù)據(jù)結(jié)構(gòu)可以是數(shù)組、二叉堆誉碴、等等

分治策略

對(duì)于任意給定的數(shù)v宦棺,S中的數(shù)被分成三組:

  1. ,比v小的數(shù)

  2. 黔帕,與v相等的數(shù)

  3. 代咸,比v大的數(shù)
    搜索范圍縮小,轉(zhuǎn)而在S的三個(gè)子集中進(jìn)行:
    ![](http://latex.codecogs.com/svg.latex?selection(S, k) =\begin{cases}selection(S_L, k) & if ; k<=|S_L| \v & if ; |S_L| < k <= |S_L| + |S_V| \selection(S_R, k-|S_L|-|S_V|) & if ; k > |S_L| + |S_V| \\end{cases})

在理想情況下成黄,算法T(n) = T(n/2) + O(n)呐芥,時(shí)間復(fù)雜度為O(n)

基準(zhǔn)v的選擇see also 快速排序

分治策略的實(shí)現(xiàn)

由于需要多維護(hù)一個(gè)

,partition()中將S分為
,
,

三個(gè)子集不易實(shí)現(xiàn)奋岁。


其中基準(zhǔn)v為5思瘟,指針l左側(cè)l為比基準(zhǔn)v小的數(shù),而指針m左側(cè)為不超過基準(zhǔn)的數(shù)闻伶。當(dāng)分割時(shí)遇到比基準(zhǔn)小的數(shù)時(shí)滨攻,需要將

兩個(gè)子集整體向右移動(dòng)一位,耗費(fèi)極大時(shí)間

因此,實(shí)現(xiàn)時(shí)可將上述的三組放寬為:

  1. 光绕,不超過v的數(shù)

  2. v
  3. 更鲁,不小于v的數(shù)

顯然,該變形不改變正確性

see implement: divide.FindKMin

快速傅里葉(Fourier)變換
值表示法

多項(xiàng)式具有如下性質(zhì)

一個(gè)d次多項(xiàng)式被其在d+1個(gè)不同點(diǎn)處的取值所唯一確定
如:d=1時(shí)奇钞,即任意兩點(diǎn)確定一條直線

該性質(zhì)引出d次多項(xiàng)式的值表示法澡为。

因此,對(duì)于一個(gè)d次多項(xiàng)式
![](http://latex.codecogs.com/svg.latex?A(x) = a_0 + a_1x^1 + a_2x^2 + ... + a_dx^d)
有如下兩種表示法(該表示法能夠唯一確定該多項(xiàng)式):

  1. 系數(shù)表示法:多項(xiàng)式的系數(shù)a_0, a_1, a_2 .... a_d
  2. 值表示法:A(x_0), A(x_1), A(x_2) .... A(x_d)的值

在值表示法下景埃,對(duì)于多項(xiàng)式相乘問題媒至,只要把

相乘,即可得到
的值谷徙,多項(xiàng)式相乘成為線性問題

在多項(xiàng)式乘法中拒啰,只要將多項(xiàng)式的變量x換成基數(shù)2,并留意進(jìn)位完慧,即可得到二進(jìn)制乘法
多項(xiàng)式乘法的應(yīng)用:信號(hào)處理
系數(shù)表示法和值表示法可以相互轉(zhuǎn)換谋旦,系數(shù)到值的過程稱為計(jì)算,值到系數(shù)的過程稱為插值

求解多項(xiàng)式相乘(A*B=C)

計(jì)算這步時(shí)間復(fù)雜度為

册着。

若對(duì)![](http://latex.codecogs.com/svg.latex?x_0, x_1, ..., x{n-1})的選取有一定技巧,則可使計(jì)算過程之間產(chǎn)生重復(fù)步驟脾歧,從而節(jié)省算法的時(shí)間甲捏。快速

變換就是基于此將時(shí)間復(fù)雜度降為

若選擇它們?yōu)檎?fù)數(shù)對(duì)鞭执,即![](http://latex.codecogs.com/svg.latex?+-x_0, +-x_1, ...., +-x_{n/2-1})司顿。若以

為例,將它的奇次冪和偶次冪分離兄纺,則大溜,

![](http://latex.codecogs.com/svg.latex?= (3+4x+6x^2) + x(4+2x2+10x4) = A_e(x^2) + xA_o(x^2))

則,

![](http://latex.codecogs.com/svg.latex?A(x_i) = A_e(x_i^2) + x_iA_o(x_i^2))

![](http://latex.codecogs.com/svg.latex?A(-x_i) = A_e(x_i^2) - x_iA_o(x_i^2))

若對(duì)于正負(fù)數(shù)對(duì)的使用從遞歸頂層一直到到底層估脆,那么其運(yùn)算時(shí)間滿足

![](http://latex.codecogs.com/svg.latex?T(n) = 2T(n/2) + O(n))

假設(shè)我們底層選擇的數(shù)選擇為1钦奋,那么遞歸頂層選擇的n個(gè)數(shù),它們應(yīng)該是旁蔼,1的n次復(fù)根锨苏,即等式![](http://latex.codecogs.com/svg.latex?z^n = 1) 的n個(gè)復(fù)數(shù)解。

復(fù)根的理解如下:

插值TODO
寫在最后
  • 立個(gè)Flag棺聊,TODO will be done some day伞租。
  • 渣代碼,且輕噴?:worried:?限佩。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末葵诈,一起剝皮案震驚了整個(gè)濱河市裸弦,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌作喘,老刑警劉巖理疙,帶你破解...
    沈念sama閱讀 211,561評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異泞坦,居然都是意外死亡窖贤,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,218評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門贰锁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來赃梧,“玉大人,你說我怎么就攤上這事豌熄∈卩郑” “怎么了?”我有些...
    開封第一講書人閱讀 157,162評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵锣险,是天一觀的道長蹄皱。 經(jīng)常有香客問我,道長芯肤,這世上最難降的妖魔是什么巷折? 我笑而不...
    開封第一講書人閱讀 56,470評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮纷妆,結(jié)果婚禮上盔几,老公的妹妹穿的比我還像新娘晴弃。我一直安慰自己掩幢,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,550評(píng)論 6 385
  • 文/花漫 我一把揭開白布上鞠。 她就那樣靜靜地躺著际邻,像睡著了一般。 火紅的嫁衣襯著肌膚如雪芍阎。 梳的紋絲不亂的頭發(fā)上世曾,一...
    開封第一講書人閱讀 49,806評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音谴咸,去河邊找鬼轮听。 笑死,一個(gè)胖子當(dāng)著我的面吹牛岭佳,可吹牛的內(nèi)容都是我干的血巍。 我是一名探鬼主播,決...
    沈念sama閱讀 38,951評(píng)論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼珊随,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼述寡!你這毒婦竟也來了柿隙?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,712評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤鲫凶,失蹤者是張志新(化名)和其女友劉穎禀崖,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體螟炫,經(jīng)...
    沈念sama閱讀 44,166評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡波附,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,510評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了昼钻。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片叶雹。...
    茶點(diǎn)故事閱讀 38,643評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖换吧,靈堂內(nèi)的尸體忽然破棺而出折晦,到底是詐尸還是另有隱情,我是刑警寧澤沾瓦,帶...
    沈念sama閱讀 34,306評(píng)論 4 330
  • 正文 年R本政府宣布满着,位于F島的核電站,受9級(jí)特大地震影響贯莺,放射性物質(zhì)發(fā)生泄漏风喇。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,930評(píng)論 3 313
  • 文/蒙蒙 一缕探、第九天 我趴在偏房一處隱蔽的房頂上張望魂莫。 院中可真熱鬧,春花似錦爹耗、人聲如沸耙考。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,745評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽倦始。三九已至,卻和暖如春山卦,著一層夾襖步出監(jiān)牢的瞬間鞋邑,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,983評(píng)論 1 266
  • 我被黑心中介騙來泰國打工账蓉, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留枚碗,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,351評(píng)論 2 360
  • 正文 我出身青樓铸本,卻偏偏與公主長得像肮雨,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子归敬,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,509評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • 算法和數(shù)據(jù)結(jié)構(gòu) [TOC] 算法 函數(shù)的增長 漸近記號(hào) 用來描述算法漸近運(yùn)行時(shí)間的記號(hào)酷含,根據(jù)定義域?yàn)樽匀粩?shù)集$N=...
    wxainn閱讀 1,059評(píng)論 0 0
  • 1 序 2016年6月25日夜鄙早,帝都,天下著大雨椅亚,拖著行李箱和同學(xué)在校門口照了最后一張合照限番,搬離寢室打車去了提前租...
    RichardJieChen閱讀 5,082評(píng)論 0 12
  • 概述:排序有內(nèi)部排序和外部排序,內(nèi)部排序是數(shù)據(jù)記錄在內(nèi)存中進(jìn)行排序呀舔,而外部排序是因排序的數(shù)據(jù)很大弥虐,一次不能容納全部...
    每天刷兩次牙閱讀 3,729評(píng)論 0 15
  • #define UIColorFromRGB(rgbValue) [UIColor colorWithRed:((...
    keelZJP閱讀 170評(píng)論 0 0