分治法实现求解最大子数组问题
一、最大子数组问题描述
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
例子:
输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大为 6。
题目源于力扣网
二、分治法三步骤
1.分解原问题:将问题划分成一些子问题,子问题相互独立且与原问题相同,只是规模更小。
2.解决子问题:递归求解子问题。当子问题足够小,不能划分直接求解。
3.合并问题解:将子问题的解合并成原问题的解。
三、求解最大子数组组
分治法求解就是找三个子区域内的数组最大和:
1)完全位于子数组A[left…mid]中, left<=i<=j<=mid;
2)完全位于子数组A[mid + 1…right]中,mid<=i<=j<=right;
3)跨越了中点,left<=i<=mid<j<=right;
最后我们的解一定是在这三个部分中的最大的那一个。
/*输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大为 6。*/
#include<iostream>
using namespace std;
int FindMaxCrossArray(int a[],int left,int right)//用于求跨过中点的最大子数组和
{
int sum = 0;//用于存放数组的和
int leftsum=0;//用于存放数组下标left~mid之间最大和
int rightsum=0;//用于存放数组下标mid+1~right之间最大和
int mid=(left+right)/2;//下标最中间
int i;
for(i=mid;i>=left;i--)
{
sum+=a[i];
if(sum > leftsum)
leftsum=sum;
}
sum=0;//sum需要重新归为0
for(i=(mid+1);i<=right;i++)
{
sum+=a[i];
if(sum > rightsum)
rightsum=sum;
}
return leftsum+rightsum;
}
int FindMax(int a[],int left,int right)
{
int leftmax,rightmax,crossmax;
int mid;
mid = (left+right)/2;
if(left==right)
return a[left];
else
{
leftmax = FindMax(a,left,mid);//利用递归划分数组
rightmax = FindMax(a,mid+1,right);//利用递归划分数组
crossmax = FindMaxCrossArray(a,left,right);
}
if(leftmax>=rightmax && leftmax>=crossmax)
return leftmax;
else if (rightmax>=leftmax && rightmax>=crossmax)
return rightmax;
else
return crossmax;
}
int main(void)
{
int a[100],n;
cout<<"Input Array Length"<<endl;
cin>>n;
cout<<"Input Array"<<endl;
for(int i=0;i<n;i++)
{
cin>>a[i];
}
cout<<"最大子数组和为:"<<FindMax(a,0,n-1)<<endl;
return 0;
}