您的位置:首页 > 其它

最大子数组问题

2016-04-23 14:49 281 查看
1. 问题描述

最大子数组问题: 寻找数组的和最大的非空连续数组.

2. 问题求解

2.1 分治法求解

思想:将数组划分为两个规模一样大的子数组, 找到子数组的中间位置mid,数组A[low:high]的任何连续子数组A[i:j]的所处的位置肯定是一下三种情况之一:

(1) 完全位于子数组A[low:mid]中, low<=i<=j<=mid;

(2)完全位于子数组A[mid+1:high]中, 因此mid<i<=j<=high

(3)跨越了中点,因此low<=i<=mid<j<=high

然后再这三种情况中找到最大值.

基本情况: 数组只有一个元素;

递归情况: 当前数组大小大于1,便进行分解.

时间复杂度分析:T(n)=2T(n/2)+O(n) O(n) = nlogn

以下是java实现代码:

public static int maxArraySum(int[] num, int low, int high){
if(low==high) //基本情况
return num[low];

int mid;
int leftmax=0;
int rightmax=0,midmax=0;

mid = (low+high)/2;
leftmax=maxArraySum(num,low,mid);
rightmax=maxArraySum(num,mid+1,high);
midmax = maxMidArraySum(num,low,mid,high);

//求以上三种情况的最大值
if(leftmax<midmax)
leftmax=midmax;

if(leftmax<rightmax)
leftmax=rightmax;

return leftmax;

}

//求包含中间元素值的数组的最大和
public static int maxMidArraySum(int[] num,int low,int mid,int high){
int max;
//找从中间值开始左边最大的和
int leftmax=Integer.MIN_VALUE;  //mid左边的最大和 ,不取0的原因是要考虑负数
int sum=0;
int leftindex=mid; //存储最大子数组和的最左边的下标
for(int i=mid-1;i>=low;i--){
sum += num[i];
if(sum > leftmax){
leftmax = sum;
leftindex = i;
}
}

//找从mid开始右边的最大的和
int rightmax = Integer.MIN_VALUE;//mid右边的最大和
sum = 0;
int rightindex = mid; //存储最大子数组和的最右边的下标
for(int i=mid+1;i<=high;i++){
sum += num[i];
if(sum>rightmax){
rightmax=sum;
rightindex=i;
}
}
return leftmax+num[mid]+rightmax;
}

public static void main(String[] args){
int[] num={13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7};
System.out.println(maxArraySum(num,0,num.length-1));
}
2.2 非递归/线性求解方法

思路: 使用2个辅助数组, maxSum[len] 和 iSum[len] ;

其中前者maxSum[i]表示,前i个元素构成的最大子数组和,不一定包含第i个元素. 可以分为包含第i个元素和不包含第i个元素这两种情况.

后者iSum[i]表示一定包含第i个元素的最大子数组和. 这又分为2种情况:一种只包含第i个元素num[i];一种是当前元素加上包含第i-1个元素的最大值,即iSum[i-1]+num[i]

时间复杂度:O(n)

实现代码如下:

public static int maxSum(int[] num){
int max = Integer.MIN_VALUE;
int len = num.length;
int[] maxSum = new int[len];//每一项记录前i个元素的最大和,不一定包含第i个元素
int[] iSum = new int[len]; //每一项记录包含当前第i个元素的最大值

maxSum[0] = num[0];
iSum[0] = num[0];

int i=1;
int k0;
for(;i<len;i++){
//不包含第i个元素
k0 = maxSum[i-1];

//包含第i个元素
if((iSum[i-1] + num[i]) > num[i])
iSum[i] = iSum[i-1] + num[i];
else
iSum[i] = num[i];

if(iSum[i] > k0)
maxSum[i] = iSum[i];
else
maxSum[i] = k0;

System.out.println(iSum[i] +" :" + maxSum[i]);

//更新当前子数组的最大和
if(maxSum[i] > max)
max = maxSum[i];
}

return max;
}
3. 问题应用

在求股票最大收益问题时,可以将股票每日价格数组转换为每天收益数组,这样原来的确定哪天买入卖出的问题便可以等价与求转换后的数组的最大子数组和.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: