在利用分治演算法求問題解時其基本思路可以分為以下幾個步驟:
(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 ...