关于最大子数组问题如果采用暴力破解法将会很容易实现,但是暴力破解复杂度可想而知,所有如果采用分治策略可以大大减少运行时间,下面将分析分治策略如何解决这个问题,通过伪代码来表示执行过程,并用Java,C++进行实现.
一.分析
先提出一个数组:
如果将一个数组划分成两个,那么最大子数组出现的位置有三个:
1.全在num[low,mid]也就是左边
2.全在nums[mid+1,high]也就是右边
3.穿过mid,一部分在左边一部分在右边,也就是案例数组的情况,用数组表示就是:
nums[low<=i<=mid,mid<j<=high]
知道这些就可以来分析分治策略了,先来看看是穿越中间的情况:
这种情况应该是从中间分别向左,向右进行求和,计算两个方向的最大求和与下标,保存后返回,如下图所示:
通过上边的分析,我们不难发现,其实求最大子数组问题的子问题就是:求通过中间的最大数组问题。
然后咱们来验证一下如图所示:
通过图片可以看出,从上到下分解问题到子问题,复杂度有所降低。
接下来通过伪代码实现一下:
FIND-MAX-CROSSING-SUBARRAY(A,low,mid,high)
left-sum = -∞
sum = 0
for i = mid downto low
{
sum = sum+A[i]
if (sum>left-sum){
left-sum = sum
max-left = i
}
}
right-sum = -∞
sum = 0
for j=mid+1 to high
{
sum = sum+A[j]
if(sum>right-sum){
right-sum = sum
max-right = j
}
}
return (max-left,max-right,left-sum + right-sum)
上边的伪代码实现的功能是,有中间开始分别向两边加和,求出最大的和,并且记录两边的索引,将信息返回
FIND-MAXIMUM-SUBARRAY(A,low,high)
if(high == low){
return (low,high,A[low])
}
else mid=[(low+high)/2]
(left-low,left-high,left-sum) = FIND-MAXIMUM-SUBARRAY(A,low,mid)
(right-low,right-high,right-sum) = FIND-MAXIMUM-SUBARRAY(A,mid+1,high)
(cross-low,cross-high,cross-sum) = FIND-MAX-CROSSING-SUBARRAY(A,low,mid,high)
if (left-sum>=right and left-sum>=cross-sum)
return (left-low,left-high,left-sum)
elseif(right-sum>=left-sum and right-sum>=cross-sum)
return (right-low,right-high,right-sum)
else return (cross-low,cross-high,cross-sum)
这一部分实现的是递归调用 FIND-MAX-CROSSING-SUBARRAY(A,low,mid,high)分解问题为子问题,并且判断哪个为最大子数组.
二.Java实现
package Main;
public class Test {
public static void main(String[] args) {
int[] nums = {13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7};
anser an = new anser();
an = FineMaxSubarray(nums,0,15); //以下标为基准
System.out.print(an.getIndex1()+" "+an.getIndex2()+" "+ an.getMax());
}
public static anser FineMaxCorssingSubarray(int[] nums,int low,int mid,int high){
int leftMax = -100; //数组中间向左方向最大值初始化
int sum = 0; //用来统计数值
int leftMaxindex = 0; //记录左最大索引
int rightMaxindex = 0; //记录右边最大索引
for(int i=mid;i>low;i--){ //进行左统计
sum=sum+nums[i];
if(sum>leftMax){
leftMax = sum;
leftMaxindex = i;
}
}
int rightMax = -100;
sum = 0;
for(int i=mid+1;i<high;i++){ //进行右统计
sum=sum+nums[i];
if(sum>rightMax){
rightMax = sum;
rightMaxindex = i;
}
}
anser an = new anser(leftMaxindex,rightMaxindex,leftMax+rightMax); //建立类保存值
return an; //返回得到的类
}
public static anser FineMaxSubarray(int[] nums,int low,int high){
if(high == low){
return new anser(low,high,nums[low]);
}
else{
int mid = (low+high)/2;
anser anleft = new anser();
anleft = FineMaxSubarray(nums,low,mid); //递归向左
anser anright = new anser();
anleft = FineMaxSubarray(nums,mid+1,high); //递归向右
anser ancross = new anser();
ancross = FineMaxCorssingSubarray(nums,low,mid,high); //获取中间
if(anleft.getMax()> ancross.getMax()&&anleft.getMax()> anright.getMax()){ //进行sum比较
return anleft;
}else if(anright.getMax()> ancross.getMax() && anright.getMax()> anleft.getMax()){
return anright;
}else{
return ancross;
}
}
}
}
运行结果:
三.C++实现
#include<iostream>
using namespace std;
typedef struct {
int index1;
int index2;
int max;
}anser;
anser FineMaxCorssingSubarray(int* nums, int low, int mid, int high) {
int leftmax = -1000;
int leftmaxindex = 0;
int sum = 0;
for (int i = mid; i > low; i--) {
sum += nums[i];
if (sum > leftmax) {
leftmax = sum;
leftmaxindex = i;
}
}
int rightmax = -1000;
int rightmaxindex = 0;
sum = 0;
for (int i = mid + 1; i < high; i++) {
sum += nums[i];
if (sum > rightmax) {
rightmax = sum;
rightmaxindex = i;
}
}
anser an;
an.index1 = leftmaxindex;
an.index2 = rightmaxindex;
an.max = leftmax + rightmax;
return an;
}
anser FineMaxSubarray(int* nums, int low, int high) {
if (low == high) {
anser an;
an.index1 = low;
an.index2 = high;
an.max = nums[low];
return an;
}
int mid = (low + high) / 2;
anser left = FineMaxSubarray(nums, low, mid);
anser right = FineMaxSubarray(nums, mid + 1, high);
anser cross = FineMaxCorssingSubarray(nums, low, mid, high);
if (left.max > right.max && left.max > cross.max) {
return left;
}
else if (right.max > left.max && right.max > cross.max) {
return right;
}
else {
return cross;
}
}
int main() {
int nums[] = {13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7};
anser an =FineMaxSubarray(nums, 0, size(nums) - 1);
cout << an.index1 << " " << an.index2 << " " << an.max;
return 0;
}
运行结果:
------------------------------------------------------------------------------------------------------------
最后希望大家可以参与一下投票,来决定下一篇文章用什么语言实现