今天看到环状连续数组求子数组最大和的题目,看了几篇博客,但是好像有问题,可以举出反例。于是参考其他人的博客自己又总结下。
首先,求非环状的数组中子数组 最大和问题是一个动态规划的思想。
sum[i] = max(sum(i-1) + a[i], a[i]); sum[i]代表以i元素结尾的子数组的最大和,sum[i-1]代表以i-1元素结尾的子数组的最大和,a[i]代表第i个元素的值,由此公式可得,以第i个元素结尾的子数组的最大和可以由它之前的以第i-1个元素结尾的子数组的最大和推导出。如果以i-1结尾子数组的最大和sum[i-1]>0,那么sum[i-1]+a[i]则就是sum[i],如果sum[i-1]<0,则以i元素结尾的最大子数组最大和就是a[i]了。那么如果数组从头到尾以每个位置元素结尾的子数组的最大和都有了,只要比较得到其中最大的值,那么就是这个数组子数组最大和的值。
求非环形连续数组字数组最大和,代码:(1)
public static int NotCircleMaxValue(int[] a){//求非环形结构时最大和字数组
if(null==a||a.length<=0)
{
System.out.println("数组不合法");
return Integer.MIN_VALUE;
}
int maxvalue=a[0],sum=0,i=0;
while(i<a.length)
{
if(sum>0)
sum+=a[i];
else
sum=a[i];
if(maxvalue<sum)
{
maxvalue=sum;
}
i++;
}
return maxvalue;
}
求环状数组中子数组 最大和问题。
思想:
求这个问题会有两种情况:
《1》如果拥有最大和的子数组就在a[0]与a[n-1]范围中。
《2》如果拥有最大和的子数组包含了a[0]与a[n-1],也就是跨越了这个收尾结合的地方。
因此对于这两种情况我们做两种处理:
《1》按照代码(1)求出非环形数组的子数组最大和
《2》利用上面动态规划思想,我们同样可以找到非环形结构中子数组的最小和,并且可以求得最小和是以哪个位置结束,也就是最小和结束元素的索引。然后,以该索引后的元素做代码(1)的处理。
最后,将两种情况得到的最大值进行比较,取其中较大的为最大和。
或许第二点有点费解,这个结论没有去证明,日后再查资料证明。
求子数组最小和结束位置代码,代码(2)
public static int getMinindex(int[] a){
if(null==a||a.length<=0)
{
System.out.println("数组不合法");
return Integer.MIN_VALUE;
}
int minvalue=a[0],sum=0,i=0,MinIndex=0;
while(i<a.length)
{
if(sum<0)
sum+=a[i];
else
sum=a[i];
if(minvalue>sum)
{
minvalue=sum;
MinIndex=i;
}
i++;
}
return MinIndex;
}
求以最小和结束位置为开始元素的子数组最大和,代码(3)
public static int CircleMaxvalue(int[] a){
int minIndex=getMinindex(a);
if(minIndex<=Integer.MIN_VALUE)
{
return Integer.MIN_VALUE;
}
int start=minIndex+1;
int maxvalue=a[start%a.length],sum=0;
for(int i=start;(i%a.length)!=minIndex;i++)
{
if(sum>0)
sum+=a[i%a.length];
else
sum=a[i%a.length];
if(maxvalue<sum)
{
maxvalue=sum;
}
}
return maxvalue;
}
下面是整体代码:
public class test {
public static int NotCircleMaxValue(int[] a){//求非环形结构时最大和字数组
if(null==a||a.length<=0)
{
System.out.println("数组不合法");
return Integer.MIN_VALUE;
}
int maxvalue=a[0],sum=0,i=0;
while(i<a.length)
{
if(sum>0)
sum+=a[i];
else
sum=a[i];
if(maxvalue<sum)
{
maxvalue=sum;
}
i++;
}
return maxvalue;
}
public static int getMinindex(int[] a){
if(null==a||a.length<=0)
{
System.out.println("数组不合法");
return Integer.MIN_VALUE;
}
int minvalue=a[0],sum=0,i=0,MinIndex=0;
while(i<a.length)
{
if(sum<0)
sum+=a[i];
else
sum=a[i];
if(minvalue>sum)
{
minvalue=sum;
MinIndex=i;
}
i++;
}
return MinIndex;
}
public static int CircleMaxvalue(int[] a){
int minIndex=getMinindex(a);
if(minIndex<=Integer.MIN_VALUE)
{
return Integer.MIN_VALUE;
}
int start=minIndex+1;
int maxvalue=a[start%a.length],sum=0;
for(int i=start;(i%a.length)!=minIndex;i++)
{
if(sum>0)
sum+=a[i%a.length];
else
sum=a[i%a.length];
if(maxvalue<sum)
{
maxvalue=sum;
}
}
return maxvalue;
}
public static void main(String[] args) {
int a[]={-1,8,-2,-3,12,4,6,3,-1,-2};
int maxnotcircle=NotCircleMaxValue(a);
int maxcircle=CircleMaxvalue(a);
System.out.println(maxnotcircle>maxcircle?maxnotcircle:maxcircle);
}
}
结果:29
顺便列出几个测试其他博客代码出现问题的数组序列{-3,8,-2,-3,12,4,6,3,-1,-2};
{1,-4,8,-2,-3,12,4,6,3,-1,-2};