最大子数组问题的分治求解算法
2016-10-02 18:13
399 查看
最大子数组问题,就是寻找一个数组内连续元素之和最大的子数组,如数组[1,-2,3,4,5,-6],则最大子数组为[3,4,5]。当然,只有当数组内有负数值时才有意义,如果全部为正数,则最大子数组就是其本身。
假如有数组
假如最大子数组在左部分或右部分,其仍是一个最大子数组问题,只是规模更小,因此可递归地求解
假如数组横跨左右两个部分,则从中间索引
现在我们可以分别求得三个部分的最大子数组:左部的最大子数组、右部的最大子数组、横跨左右部的最大子数组。然后对其元素和进行比较。拥有最大元素和的最大子数组即所求。
下面是算法实现:
假如有数组
arr下标从
low到
high,以中点索引
mid作为区分,索引
low~mid为左部分,
mid+1~high为右部分,则最大子数组可能存在于左部分、右部分以及横跨左右部分。
假如最大子数组在左部分或右部分,其仍是一个最大子数组问题,只是规模更小,因此可递归地求解
arr[low~mid]和
arr[mid+1~high]的最大子数组。
假如数组横跨左右两个部分,则从中间索引
mid开始,向
low和
high延伸,先找到
arr[mid~low]中的最大子数组(注意,从
mid开始向两边找),然后找到
arr[mid+1~high]的最大子数组。最后将两边的最大子数组进行合并,即求出横跨左右部分的最大子数组。
现在我们可以分别求得三个部分的最大子数组:左部的最大子数组、右部的最大子数组、横跨左右部的最大子数组。然后对其元素和进行比较。拥有最大元素和的最大子数组即所求。
下面是算法实现:
#include<iostream> using namespace std; //用于将求得的最大子数组信息进行打包 struct subarray_info{ int left; //左界 int right; //右界 int sum; //最大子数组和 }; //寻找横跨左右两部分的最大子数组,并打包成subarray_info结构 void find_max_crossing_subarray(int* arr,int low,int mid,int high,subarray_info* psub){ int sum=0; int left_sum=-10000; //左部分最大子数组和 int right_sum=-10000; //右部分最大子数组和 for(int i=mid;i>=low;i--){ //从mid开始,到low,求得左部的最大子数组 sum+=arr[i]; //和大于left_sum,则求得更大的子数组 if(left_sum<sum){ left_sum=sum; psub->left=i; //更新最大子数组左界信息,左界即此最大子数组在arr中的左部索引 } } sum=0; for(int i=mid+1;i<=high;i++){ //从mid+1开始,到high,求得右部的最大子数组 sum+=arr[i]; if(right_sum<sum){ //同上 right_sum=sum; psub->right=i; //更新最大子数组右界信息 } } psub->sum=left_sum+right_sum; //最大子数组的和即左右部分最大子数组元素和的和 } //寻找arr下标从low到high的最大子数组,并将其信息打包成subarray_info结构 void find_maximum_subarray(int* arr,int low,int high,subarray_info* psub){ if(low==high){ //所求的数组只有一个元素值 psub->left=low; psub->right=high; psub->sum=arr[low]; } else{ //所求的数组有多个元素 int mid=(low+high)/2; //获取中间索引 //分别用不同的subarray_info来保存不同部分的最大子数组 subarray_info* p1=new subarray_info(); subarray_info* p2=new subarray_info(); subarray_info* p3=new subarray_info(); find_maximum_subarray(arr,low,mid,p1); //左部最大子数组 find_maximum_subarray(arr,mid+1,high,p2); //右部最大子数组 find_max_crossing_subarray(arr,low,mid,high,p3); //横跨左右部分的最大子数组 int sum1=p1->sum; //左部最大子数组的和 int sum2=p2->sum; //右部 int sum3=p3->sum; //横跨左右部 if(sum1>=sum2 && sum1>=sum3){ //左部的最大,更新psub psub->left=p1->left; psub->right=p1->right; psub->sum=p1->sum; } else if(sum2>=sum1 && sum2>=sum3){ //右部的最大 psub->left=p2->left; psub->right=p2->right; psub->sum=p2->sum; } else{ //横跨两部分的最大 psub->left=p3->left; psub->right=p3->right; psub->sum=p3->sum; } } } int main(){ int arr[16]={13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7}; subarray_info* psub=new subarray_info(); find_maximum_subarray(arr,0,15,psub); cout<<"左界:"<<psub->left<<endl; cout<<"右界:"<<psub->right<<endl; cout<<"最大子数组元素和:"<<psub->sum<<endl; return 0; } RESULT: 左界:7 右界:10 最大子数组元素和:43
相关文章推荐
- 第四章 分治策略 4.1 最大子数组问题 (暴力求解算法)
- 第四章 分治策略 4.1 最大子数组问题 (暴力求解算法)
- 【算法学习】最大子数组问题的分治法求解
- 求最大子数组的和,算法导论之分治递归求解,暴力求解,记忆扫描方法。
- 分治策略算法之最大字数组和问题
- 【算法设计-分治】最大子数组问题
- 算法导论--分治策略求解最大子数组问题
- 算法导论:分治策略__最大子数组问题
- 最大子数组求解问题(算法导论)
- 第四章 分治策略——最大子数组问题
- 【软件工程】代码复审与子数组最大和线性算法寻找问题
- 分治策略求解子数组最大和并输出下标
- poj3041 最小点覆盖==二分图最大匹配 匈牙利算法求解最大匹配问题(运用DFS)
- 算法导论-分治、最大子序列问题
- 【算法导论】最大子数组问题
- 三种算法求解一个数组的子数组最大和
- homework-01 "最大子数组之和"的问题求解过程
- 【算法导论学习-007】最大子数组和问题(Maximum subarray problem)
- 最大子数组问题(分治法)--【算法导论】