用分治和遞歸的思想——尋找最大子數組

  尋找最大子數組的問題可描述爲算法

輸入:數組

  一個數組,一個低位,一個高位函數

輸出:spa

  數組中從低位到高位中,連續和最大是多少code

  首先能想到的最直接的辦法是暴力解決,遍歷全部可能的序列組合,若是有n個元素,則需遍歷的子序列有,複雜度爲n2,稍有些經驗的就能立刻意識到,有不少重複計算在裏面,好比最長的子序列計算,包含了以前全部子序列的計算。接下來咱們使用分治的思想求解這個最大子序列,前一篇博文提過,分治的思想是將大問題分解爲同等類型的子問題,再將子問題求解,而後合併子問題得出原問題的解,其中用到了遞歸的思想,由於分解獲得子問題也能夠再次分解爲更小的子問題,上一篇博文用分治的思想解決排序問題,就是著名的歸併排序,將排序的複雜度下降到nlgn。在這個問題中,咱們能夠將原數組分解爲兩個同等大小的子數組,分別求兩個子數組中的最大子數組,在比較這兩個子數組,最後得出原數組的最大子數組,可是有一點須要考慮到,就是子數組可能會穿過中心,左數組和右數組的一部分共同構成最大子數組,但這個處理顯然不能當成原問題的同等類型問題處理,並且上一篇講過,將不屬於原問題的解放在第三步合併中處理就好,因此整個問題的解決就能夠分爲三個部分。blog

  1.分解。分解原數組爲兩個相等大小(也能夠不等)的兩個數組。排序

  2.解決。分別計算兩個數組中最大的子數組,當分解到只有一個元素時,它自己即爲最大子數組。遞歸

  3.合併。計算穿過中心的最大子數組,與左右最大子數組比較後返回最大值。class

  下面給出代碼:搜索

 1 public class Main {
 2     public static void main(String args[]){
 3         int[] a = {1,-2,13,-14,2,4,5,4};
 4         int b = 0;
 5         b = FMS(a,0,7);
 6         while(true);
 7     }
 8   //尋找跨越中心的最大子數組
 9     public static int FMCS(int[] a,int low,int mid,int high){
10         int left_sum = 0,right_sum = 0;
11         int sum = 0;
12         int max_left = 0,max_right = 0;
13         for(int i = mid;i>=low;i--){
14             sum += a[i];
15             if(sum > left_sum){
16                 left_sum = sum;
17                 max_left = i;
18             }
19         }
20         sum = 0;
21         for(int j = mid + 1;j <= high;j++){
22             sum += a[j];
23             if(sum > right_sum){
24                 right_sum = sum;
25                 max_right = j;
26             }
27         }
28         return left_sum+right_sum;
29     }
30   //尋找最大子數組
31     public static int FMS(int[] a,int low,int high){
32         int left_sum = 0,right_sum = 0,cross_sum = 0;
33         int mid = 0;
34         if(low == high){
35             return a[low];
36         }
37         else{
38             mid = (low+high)/2;
39             left_sum = FMS(a,low,mid);   //這兩句可能會迷惑一下,乍一看,並無任何求左右數組的最大子數組的代碼,但仍然求出來了
40             right_sum = FMS(a,mid+1,high); //用遞歸的思想去思考,其實FMS自己即定義爲求單邊最大子數組的函數,再次使用便可,並不須要額外代碼。
41             cross_sum = FMCS(a,low,mid,high); //重點在第一個判斷上,當遞歸「探底」時,返回一個值,這個值即爲當前所求的最大子數組,就是當分解的足夠小時。
42             if(left_sum >= right_sum      //和歸併搜索同樣,其實分治加遞歸是把一個複雜的問題,轉換爲一個更加簡單的問題的一種方式,將求最大子數組轉換爲
43                 &&left_sum >= cross_sum){   //求只有--一個元素的最大子數組。歸併排序是把排序一個大數組轉換爲排序只有一個元素的數組的問題。
44                 return left_sum;         //重點在每次「探底"時的動做,和合並的動做。 合併在這個算法中體如今尋找過中值的子數組和最後的判斷。
45             }
46             else if(right_sum >= left_sum
47                 &&right_sum >= cross_sum){
48                 return right_sum;
49             }
50             else 
51                 return cross_sum;
52         }
53     }
54 }
相關文章
相關標籤/搜索