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

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

输入:

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

输出:

  数组中从低位到高位中,连续和最大是多少

  首先能想到的最直接的办法是暴力解决,遍历所有可能的序列组合,如果有n个元素,则需遍历的子序列有,复杂度为n2,稍有些经验的就能马上意识到,有很多重复计算在里面,比如最长的子序列计算,包含了之前所有子序列的计算。接下来我们使用分治的思想求解这个最大子序列,前一篇博文提过,分治的思想是将大问题分解为同等类型的子问题,再将子问题求解,然后合并子问题得出原问题的解,其中用到了递归的思想,因为分解得到子问题也可以再次分解为更小的子问题,上一篇博文用分治的思想解决排序问题,就是著名的归并排序,将排序的复杂度降低到nlgn。在这个问题中,我们可以将原数组分解为两个同等大小的子数组,分别求两个子数组中的最大子数组,在比较这两个子数组,最后得出原数组的最大子数组,但是有一点需要考虑到,就是子数组可能会穿过中心,左数组和右数组的一部分共同构成最大子数组,但这个处理显然不能当成原问题的同等类型问题处理,而且上一篇讲过,将不属于原问题的解放在第三步合并中处理就好,所以整个问题的解决就可以分为三个部分。

  1.分解。分解原数组为两个相等大小(也可以不等)的两个数组。

  2.解决。分别计算两个数组中最大的子数组,当分解到只有一个元素时,它本身即为最大子数组。

  3.合并。计算穿过中心的最大子数组,与左右最大子数组比较后返回最大值。

  下面给出代码:

 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 }
时间: 2024-08-09 13:20:14

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

算法导论4.1寻找最大子数组

寻找最大子数组 // find_max_sub_array.h #include <stdint.h> int Find_MAX_CROSSING_SUBARRAY(int* A, int low, int mid, int high, int& max_left, int& max_right, int& max_value) { int left_sum = 0xFFFFFFFF; // 不可能的最小值 int sum = 0; for(int i = mid; i

Java 数组中寻找最大子数组

程序设计思想: 依次将数组划分开,先判断一个元素的单个数组大小,接下来两个,依次上升,最后将所得结果进行比较赋值,输出最大结果. 1 package ketangTest; 2 //张生辉,康治家 2017.3.20 3 public class Test { 4 public static void main(String args[]){ 5 int b[]={-7,9,-2,84}; 6 int a[]={-7,9,-2,84,-7,9,-2,84}; 7 int max,max2,max

求最大子数组的和,算法导论只分治递归求解,暴力求解,记忆扫描方法。

#include<iostream> #include<vector> using namespace std; /*******************************************************************************************/ // 分治方法,利用递归的思想 // ugly_chen 2014.11.3 22:24 //说明:把数组分为两部分,右边部分和左边部分,要不就是右边部分和左边部分之和. // ---

求平面最近点对(分治与递归,注:最远点对用凸包求)

Quoit Design Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 36793    Accepted Submission(s): 9552 Problem Description Have you ever played quoit in a playground? Quoit is a game in which flat

二分查找思想寻找有序数组中查找最小值

思想:循环有序数组最大的特点是利用二分查找时,有一边总是有序的,利用这个特点,利用value存储历史最小值 当左边有序,则用A[low]与value比较即可得出当前左边的最小值,然后跳转到右边看是否存在更小的: 如果右边有序,则用A[mid]与value比较,得出右边的最小值,然后跳转到左边查看是否有更小的. 算法复杂度为O(logn) 代码如下: #include<iostream> #include<stdio.h> #include<assert.h> using

漫谈递归:递归的思想 --转载

为什么要用递归 编程里面估计最让人摸不着头脑的基本算法就是递归了.很多时候我们看明白一个复杂的递归都有点费时间,尤其对模型所描述的问题概念不清的时候,想要自己设计一个递归那么就更是有难度了. 很多不理解递归的人(今天在csdn里面看到一个初学者的留言),总认为递归完全没必要,用循环就可以实现,其实这是一种很肤浅的理解.因为递归之所以在程序中能风靡并不是因为他的循环,大家都知道递归分两步,递和归,那么可以知道递归对于空间性能来说,简直就是造孽,这对于追求时空完美的人来说,简直无法接接受,如果递归仅

数据结构开发(15):递归的思想与应用

0.目录 1.递归的思想 2.递归的应用 2.1 单向链表的转置 2.2 单向排序链表的合并 2.3 汉诺塔问题 2.4 全排列问题 2.5 逆序打印单链表中的偶数结点 2.6 八皇后问题 3.小结 1.递归的思想 递归是一种数学上分而自治的思想: 将原问题分解为规模较小的问题进行处理 分解后的问题与原问题的类型完全相同,但规模较小 通过小规模问题的解,能够轻易求得原问题的解 问题的分解是有限的 ( 递归不能无限进行 ) 当边界条件不满足时,分解问题 ( 递归继续进行 ) 当边界条件满足时,直接

求最大子数组的思想和代码

对于数组ai,最大子数组定义为:ai的和最大的非空连续子数组,很明显,这个概念只对既有正元素,又有负元素的数组有意义,例如,对于ai[16] = {13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7},最大子数组为{18, 20, -7, 12},此时的和为43,求解一个数组的最大子数组的算法依然是使用分治思想,把一个数组一分为二,最大子数组要么在左边,要么在右边,要么在中间,在中间则肯定包含中点,此时便可以从中点的

第四章 分治策略——最大子数组问题

最大子数组问题 方法一:暴力求解方法 我们可以很容易地设计出一个暴力方法来求解本问题:简单地尝试没对可能的子数组,共有O(n2)种 #include<iostream> using namespace std; #define INT_MIN 0x80000000 int main() { int arr[10]={9,8,-3,-5,7,-39,79,-37,8,9}; int i,j; int sum=0,maxsum=INT_MIN; int imax; for(i=0;i<10;