第二章 分治算法
1. 分治算法的原理
分治法的基本思想是將一個規模為N的問題分解為K個規模較小的子問題,這些子問題相互獨立且與原問題性質相同。遞歸地解這些子問題,然后將各子問題的解合並得到原問題的解。
分治法所能解決的問題一般具有以下幾個特征(這部分參考了這篇博文http://blog.csdn.net/com_stu_zhang/article/details/7233761):
1) 該問題的規模縮小到一定的程度就可以容易地解決
2) 該問題可以分解為若干個規模較小的相同問題,即該問題具有最優子結構性質。
3) 利用該問題分解出的子問題的解可以合並為該問題的解;
4) 該問題所分解出的各個子問題是相互獨立的,即子問題之間不包含公共的子子問題。
第三條特征是關鍵,能否利用分治法完全取決於問題是否具有第三條特征,如果具備了第一條和第二條特征,而不具備第三條特征,則可以考慮用貪心法或動態規划法。
第四條特征涉及到分治法的效率,如果各子問題是不獨立的則分治法要做許多不必要的工作,重復地解公共的子問題,此時雖然可用分治法,但一般用動態規划法較好。
分治法的分析過程:
即總共的復雜度=划分為多個子問題的復雜度+求解各個子問題的復雜度+合並子問題的復雜度,用這個便可以建立遞歸方程,再利用上一章和的估計與界限中的第三種方法:遞歸方程 便可以得到時間復雜度了,當然也可以套用主定理。
2. 使用分治法解決的一些經典問題
(1)歸並排序
歸並排序的分治策略是將整個n個數分為左邊,右邊各一半,每個部分歸並排序的時間復雜度為T(n/2),總共有兩部分,所以求解子問題的復雜是2T(n/2)。划分子問題不需要什么多余的操作計算,直接取左右部即可,所以忽略不計。至於合並子問題操作,是將左部排好序的n/2個數和右部排好序的n/2個數合並成一個有序的數組,歸並排序的合並步是比較二個數列的第一個數,誰小就先取誰,取了后就在對應數列中刪除這個數。然后再進行比較,如果有數列為空,那直接將另一個數列的數據依次取出即可,可以看出合並有序數列的效率是比較高的,可以達到O(n)。所以整個歸並排序的時間復雜度T(n)=2T(n/2)+O(n),有了遞歸方程,套用主定理:
這里的的f(n)的階是O(n), a=2, b=2, 是n,所以
,則立即推出歸並排序的時間復雜度是:Θ (nlogn) ,不過這里我有個疑問就是:按照主定理結果是Θ (nlogn),但是我網上搜了下歸並排序的時間復雜度結果都是O(nlogn),歸並排序的最好、最壞和平均時間復雜度都是O(nlogn),不過我看一般的書算時間復雜度是只用到了 O 記號,Ω 和 Θ 幾乎沒用過。。。。。 還有就是上一章講到復雜函數的階的時候,ppt把T(n)=Θ(f(n)) 定義為 “給出了算法時間復雜度的上界和下界”,意思就是如果T(n)=Θ(f(n)) 那就可以推出T(n)=O(f(n))和T(n)=Ω(f(n))?。。。。。是這樣的么?拿不准啊。。。希望有大佬幫我答疑解惑下,感激不盡。
2017/1/6 今天看了算法導論,明白了這個問題,根據第28頁的定理3.1: 對任意兩個函數f(n)和g(n), 我們有f(n)=Θ(g(n)), 當且僅當f(n)=O(g(n))且f(n)=Ω(g(n)). 驗證了我的想法
(2)找最大值
為什么總比較次數是n-1呢?很簡單,上面是個二叉樹結構,每個數節點會比較一次,比較次數是樹的節點數,最下層應該有 n/2 個葉節點,對於二叉樹來說,葉子節點數=度為2的節點數+1,所以推出度為2的節點的數量是 n/2-1, 所以上面的整個樹共有n/2+n/2-1=n-1個節點, 即共有n-1次大小的比較。
(3)折半搜索
(4)大整數乘法
其中需要理解的是這個是怎么來的,AC,AD,BC,BD這四象都是n/2位數乘n/2位數,所以總共的復雜度是4T(n/2),AD+BC 二進制整數和二進制整數想加,一位一位的加,故復雜度是Θ(n)。
(5)矩陣乘法
n/2*n/2的矩陣共有n/2*n/2=n2/4個元素,那么矩陣之間的加減操作的復雜度便是Θ(n2)
(6)快速排序
(7)求第k小元素
怎么理解這個呢?畫一副圖就知道了:
一列表示一組5個數,取中間的一組數,再取這組數的第M/2小的元素m,圖上畫的把中間這組數排好序了,那么大於m的數至少有圖中圈的那么多,因為最后一組可能不足3個,以及m所在的那組下面只有兩個(m不能算在內了),所以這里排除了最后一列和中間那一列。那么我們繼續:
即求第k小元素總的時間復雜度 = 將整個數組划分為n/5(向上取整)並每組排序的時間復雜度O(n)+從每組第3個元素構成的數組M中尋找m的時間復雜度T(n/5)+Conquer的時間復雜度T((7n/10)+6)
(8)堆排序
這個理解起來比較容易,pass掉,記住時間復雜度是O(nlogn)
(9)最近點對
在二維平面上的n個點中找距離最近的兩個點,輸入是一系列的點,輸出距離最近的兩個點
好難理解。。。。。。,難點是在於如何理解在臨界區查找距離小於d的點對這塊,煩煩煩。還是一步步來分析吧:
思考路徑:將所有的點按照x坐標值和y坐標值排序——>按照x軸分成大小相等的兩個子集合——>遞歸地找這兩個子集合中的最近點對,設為d
現在問題就是:最近點對有可能是橫跨左右兩個集合的,在左集合和右集合各取一點所得到的點對,其中最小的距離能夠小於d的話,那么這個點對便是整個點集合的最近點對了。所以現在按照x軸的中間線往左往右各推d距離(任何一邊不可能大於d,否則大於d的那部分的點到右集合的距離肯定是大於d的)。
現在有一個理解的關鍵點:如果在左部任取一點pl,假設在右部能找到和它距離小於d的點qr,那么應該滿足兩個條件:
1. pl和qr的距離小於d 2. 因為d是左右兩部分的最近點對的距離,所以右部任何兩個點的距離都不可能小於d,即qr和它所在的那個區間的所有點的距離都不小於d
由上述可以推出對於左部的點pl,滿足上述兩個條件的的點在右部最多只有6個。現在來解釋這個:對於左部的任意一點pl,與它構成距離小於d的右部的點一定是落在矩形R中(p為圓心,d為半徑作圓,再取極端情況pl落在中位分割線上即可得此結論)。將矩形R的長為2d的邊3等分,長為d的邊2等分), 由此導出6個(d/2)x(2d/3)的矩形:
現在利用鴿舍原理,原理1: 把多於n+1個的物體放到n個抽屜里,則至少有一個抽屜里的東西不少於兩件。假設矩形R中有多於6個點,那么6個矩形中至少有一個有2個以上的點,假設u,v是位於同一小矩形中的的2個點,則
即distance(u,v)<=5d/6<d. 這與d的意義相矛盾,由此反證推出矩形R中最多只能有6個點。解決了這個,現在的問題是如何找這6個點呢?將左部的點pl和右部所有的點投影到垂線上(中位分割線)上,由於能與點pl一起構距離小於d的點一定在矩形R中,所以他們在
上的投影點距pl在
上投影點的距離小於d。由上面的分析可知這種投影點最多只有6個,因此,若將左部和右部中所有的點按照其y坐標排好序,對左部中的所有點,對排好序的點列做一次掃描,就可以找出所有最近點對的候選者。對左部中的每一點最多只要檢查右部中排好序的相繼6個點。
分治法求最近點對的時間復雜度:
(10)快速傅立葉變換
ppt這塊完全看不明白。。。。。。汗啊。。。。 上課不認真聽的后果ToT。時間復雜度是nlogn
(11)尋找凸包
找到最下最左頂點,其他頂點與它連線,按夾角從小到大排序,夾角最小的開始尋找凸包點。
可以看到這里連線是有講究的,如果與與下一頂點的連線在上一連線的右側(如p2到p3),那么就刪除和下一頂點的連線上一連線,將上一點(如p1)直接和下一點連接起來,再作如此判斷。這就是Graham-scan的基本思想。總的時間復雜度是O(nlogn)。現在怎么利用分治法來解決尋找凸包問題呢?
分治法尋找凸包的平均時間復雜度是O(nlogn),最壞情況是O(n2)。注意這里遞歸划分自區間,每次找的是距離划分直線最遠的點。
3. 平衡的概念
關於小節的總結就是:在使用分治法和遞歸時要盡量把問題分成規模相等,或至少是規模相近的子問題,即平衡。