【转】算法导论学习笔记 一 分治算法
分治策略是一種常見的算法。在分治策略中,我們遞歸的求解一個(gè)問題,在每層遞歸中應(yīng)用如下三個(gè)步驟: 1. 分解,將問題分解成規(guī)模更小但解決方案相同的子問題 2. 解決,遞歸的求解子問題,如果子問題足夠小則停止遞歸,直接求解 3. 合并,將子問題的解組合成原問題的解
最大字?jǐn)?shù)組問題
給你一段股市的波動(dòng)圖,找到在什么時(shí)候買入,什么時(shí)候賣出能獲得最大的收益。
?
暴力破解法
我們很容易的想到一個(gè)包里破解法,就是把所有買入,賣出的組合列舉出來(lái)進(jìn)行對(duì)比,n天中取任意兩天作為買入日和賣出日,共有n*(n-1)/2種解法,因此這種解法的時(shí)間復(fù)雜度是O(n^2)。
問題變換
為了方便我們處理,我們把每個(gè)數(shù)組的值變?yōu)楣善钡膬粼隽俊_@個(gè)時(shí)候,最佳解法就變成了求一個(gè)數(shù)組的最大字?jǐn)?shù)組:
?
使用分治策略的求解法
我們可以認(rèn)為,我們要尋找子數(shù)組array[start,end]的最大字?jǐn)?shù)組分三種情況:
- 最大字?jǐn)?shù)組在左半部分
- 最大字?jǐn)?shù)組在右半部分
- 最大字?jǐn)?shù)組起點(diǎn)在左半部分,終點(diǎn)在右半部分
對(duì)于前兩種情況,我們的求解方式和分解前是相同的,我們需要單獨(dú)處理第三種情況。
如圖:
?
那么我們給出解這個(gè)問題的思路:
FindMaxCrossingSubArray(array,start,end)mid=(start+end)/2從mid開始向左找,找到以mid為終點(diǎn)的最大字?jǐn)?shù)組為array[max-left,min]從mid開始向右找,找到以mid為起點(diǎn)的最大字?jǐn)?shù)組array[min,max-right]跨越mid的最大字?jǐn)?shù)組為array[max-left,max-right]max-leftchild =FindMaxCrossingSubArray(array,start,mid)max-rightchild =FindMaxCrossingSubArray(array,min,end)return max-leftchild,max-rightchild,array[max-left,max-right] 3個(gè)中的最大字?jǐn)?shù)組分治算法分析
這種方法我們需要遍歷的次數(shù)會(huì)比n^2少一些,時(shí)間復(fù)雜度為O(nlgn)
代碼實(shí)現(xiàn)
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | public?int[] FindRecrusive(int[] array,?int?low,?int?high) { ????Console.WriteLine("low {0}, high {1}", low, high); ? ????if?(low == high) ????{ ????????return?new[] { low, high, array[low] }; ????} ????int?mid = (low + high) / 2; ? ????int?leftmaxsum =?int.MinValue; ????int?currentleftsum = 0; ????int?leftmaxlocation = mid; ? ????for?(int?i = mid; i >= low; i--) ????{ ????????currentleftsum += array[i]; ????????if?(currentleftsum > leftmaxsum) ????????{ ????????????leftmaxsum = currentleftsum; ????????????leftmaxlocation = i; ????????} ????} ? ????int?rightmaxsum = 0; ????int?currentrightsum = 0; ????int?rightmaxlocation = mid; ? ????for?(int?j = mid + 1; j <= high; j++) ????{ ????????currentrightsum += array[j]; ????????if?(currentrightsum > rightmaxsum) ????????{ ????????????rightmaxsum = currentrightsum; ????????????rightmaxlocation = j; ????????} ????} ? ????int[] result =?new[] { leftmaxlocation, rightmaxlocation, leftmaxsum + rightmaxsum }; ? ????int[] leftresult = FindRecrusive(array, 0, mid); ? ????if?(leftresult[2] > result[2]) ????{ ????????result = leftresult; ????} ? ????int[] rightresult = FindRecrusive(array, mid + 1, high); ????if?(rightresult[2] > result[2]) ????{ ????????result = rightresult; ????} ? ????return?result; } |
自己嘗試用C#實(shí)現(xiàn)了下,托管在了github上
總結(jié)
以上是生活随笔為你收集整理的【转】算法导论学习笔记 一 分治算法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【转】1:C#的三种异步的详细介绍及实现
- 下一篇: 【转】ABP源码分析三十五:ABP中动态