用分治和递归的思想——寻找最大子数组

  寻找最大子数组的问题可描述为算法

输入:数组

  一个数组,一个低位,一个高位函数

输出: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 }
相关文章
相关标签/搜索