分治演算法的深入理解

2021-10-05 10:29:03 字數 3547 閱讀 8992

在利用分治演算法求問題解時其基本思路可以分為以下幾個步驟:

(1)分解,將要解決的問題劃分成若干規模較小的同類問題

(2)求解,當子問題劃分得足夠小時,用較簡單的方法解決

(3)合併,按原問題的要求,將子問題的解逐層合併構成原問題的解.

下面我們將通過具體的例項來對以上步驟做出詳細的分析。

給定乙個整數陣列 nums ,找到乙個具有最大和的連續子陣列(子陣列最少包含乙個元素),返回其最大和

示例:

輸入: [-2,1,-3,4,-1,2,1,-5,4]

輸出: 6

解釋: 連續子陣列 [4,-1,2,1] 的和最大,為 6。

問題分析:

我們要求最大子串行的和,就要先找到最大子串行的位置。那麼最大子串行在哪呢?我們將陣列二分,設定 mid=(low=high)/2 ,最大子串行要麼在mid的左邊[low,mid],要麼在mid的右邊[mid+1,high],要麼跨立在分界點上。哪什麼又叫做"跨立在分界點上"呢?只有包含子串行[mid,mid+1]的序列才叫做"跨立在分界點上"。通俗的將就是包含左邊序列的最後乙個元素mid和右邊第乙個元素mid+1的序列。在了解了"跨立"的含義後,我們又應該如何去解決求各個子串行的最大值呢?這其中又要利用到線性動態規劃的思想(詳解請見另一篇文章)。我們以左子串行為例,-2,1,-3,4,-1,連續的子串行可以分為以-2結尾的子串行,以1結尾的子串行,以-3結尾的子串行…我們假設以各數結尾的最大子串行的值為b[j],那麼與j緊鄰的i(i>j)結尾的最大值為max,用狀態轉移方程式表示為b[i] max.

/*

動態規劃

時間複雜度o(n),空間複雜度o(1)

*/public

class

main

;//測試資料

int[

] b =

newint[9

];//用來記錄各個狀態的最大值

system.out.

println

(continuesubmax

(date,b));

}//求最大連續子陣列的和

public

static

intcontinuesubmax

(int

date,

int[

] b)

}return max;

}}

有如上的基礎後,我們可以配合分治的思想來解決此問題。我們又該如何求"跨立"序列的最大值呢?由於跨立序列必然包含子串行[mid,mid+1],其中mid為左子串行的結尾,mid+1為右子串行的開頭,所以問題轉化為跨立序列的最大值 = 以mid結尾的左子串行的最大值+以mid+1開頭的右子串行的最大值

/*

分治法時間複雜度o(nlogn),空間複雜度o(logn)遞迴時棧使用的空間

*/public

class

main

;// 測試資料

system.out.

println

(continuesubmax(0

,8,date));

}//求最大連續子陣列的和

public

static

intcontinuesubmax

(int low,

int high,

int[

] date)

int mid =

(low+high)/2

;//二分區間

int lm =

continuesubmax

(low,mid,date)

;//左子串行的最大值

int rm =

continuesubmax

(mid+

1,high,date)

;//右子串行的最大值

//從mid開始依次往前找到以mid結尾的左子串行的最大值

int leftmax = date[mid]

;int leftsum =0;

for(

int i=mid;i>=low;i--

)//從mid+1開始依次往後找到以mid+1加一開頭的右子串行的最大值

int rightmax = date[mid+1]

;int rightsum =0;

for(

int i=mid+

1;i<=high;i++

)//跨立序列的最大值

int cm = leftmax + rightmax;

return math.

max(cm,math.

max(lm,rm));

}}

給定乙個長度為 n+1 的陣列nums,陣列中所有的數均在 1∼n 的範圍內,其中 n≥1。請找出陣列中任意乙個重複的數,但不能修改輸入的陣列。

樣例

給定 nums = [2, 3, 5, 4, 3, 2, 6, 7]。

返回 2 或 3。

問題分析:

首先,由題意我們可知陣列的長度為n+1,也就是說數組裝了n+1個數,又有每個數的範圍是 [1,n],那麼必然存在連個重複的數。為什麼?這便是抽屜原理-------桌上有十個蘋果,要把這十個蘋果放到九個抽屜裡,無論怎樣放,我們會發現至少會有乙個抽屜裡面放不少於兩個蘋果。這一現象就是我們所說的「抽屜原理」。 抽屜原理的一般含義為:「如果每個抽屜代表乙個集合,每乙個蘋果就可以代表乙個元素,假如有n+1個元素放到n個集合中去,其中必定有乙個集合裡至少有兩個元素。」 抽屜原理有時也被稱為鴿巢原理。由此我們可以得出基本的解題思路,首先我們將範圍區間二分為 [ 1, (1+n)/2 ] 和 [ (1+n)/2 + 1 , n],然後遍歷陣列,統計陣列分別在區間 [ 1, (1+n)/2 ] 和區間 [ (1+n)/2 + 1 , n]的個數,如果數的個數大於區間的長度,說名重複得數一定再此區間,然後再將此區間重複上訴過程,直到找到答案,即每個區間的長度變為1.

**

public

class

main

; system.out.

println

(findrepeatnumber(1

,date.length-

1,date));

}//找出重複的元素

public

static

intfindrepeatnumber

(int low,

int high,

int[

] date)}if

(count>mid-low+1)

else

}return low;

//或者return high;

}}

KMP演算法深入理解

knuth morris pratt演算法 簡稱kmp 是最常用字元傳匹配演算法之一。它以三個發明者命名,起頭的那個k就是著名科學家donald knuth。kmp演算法對於任何模式和目標序列,都可以在 線性時間 內完成匹配查詢,而不會發生退化。1 kmp演算法的原理 kmp演算法中主要的概念是ne...

深入理解KNN演算法

1.knn是個 消極 演算法,y f x1,x2,xp,x 其中x1,x2,xp是訓練資料,x是待分類或回歸查詢例項,y是分類或回歸結果.整個過程中沒有建立任何數學模型.2.與 積極 演算法的乙個關鍵差異 knn可以為不同的待分類查詢例項建立不同的目標函式逼近.3.knn的唯一假設,函式f是平滑的....

深入理解遞迴演算法

下面是對遞迴演算法執行過程的理解 結合漢諾塔問題 原始碼 public class hanoi else public static void main string args 為了方便我等下解釋執行過程,也把 的截圖貼在下面 準備工作做完了,正式開始理解過程的講解 以漢諾塔三個圓盤時為例,這裡n ...