今天看算法,看到一道题,题目描述如下:
给一个数组,找出该数组的最大子序列和。例如:数组{0,-1,-9,8,1,-8,10,-1},最大子序列为8+1-8+10=11,需要输出11。
由于很久没有写算法,遇见这个问题想了很久,大约花了一个半小时才想出来这个问题。
先贴一下代码:
package com.atguigu.java;
public class HelloWorld {
public static void main(String[] args){
int[]a={0,-1,-9,8,1,-8,10,-1};
int sum=a[0];
int max=a[0];
int summax=0;
int b=a.length;
for(int i=1;i<b;i++)
{
if(a[i]>0)
{
sum+=a[i];
}
if(a[i]<0)
{
if(a[i-1]>=0)
{
max=sum;
}
else if(sum+a[i]<=0)
{
sum=0;
if(i==b-1)
sum=a[i];
}
if(a[i]>max)
{
max=a[i];
}
if(sum+a[i]>0)
sum+=a[i];
}
if(i==b-1)
{
if(max>sum)
summax=max;
else
summax=sum;
}
}
System.out.println(summax);
}
}
输出结果如下:
解这道题的思路如下:
首先,这个数组中有正数也有负数,由于负数的存在,会使得某些子序列在加了负数之后小于零,这时,这个序列就没有价值了,可以重新开始一个新的序列。我们可以设置一个sum来装子序列的和,而max用来装最大的连续正数的和。最大连续正数的和可以在a[i]<0的前提下,通过判断a[i-1],即前一个元素是否为正数来达到目的。因为如果前一个元素为正数,而当前遍历到的元素为负数,那么之前的sum则是目前最大的正数序列的和。当数组遍历到最后一个元素的时候,sum与max进行比较,得出最大子序列的和。
上文中的这个算法的时间复杂度为O(n)。
这个问题还可以继续扩充,比如,在输出最大子序列的和的同时还需要输出对应的元素,即输出一个新的数组。这个也好办到,只需要添加一个新的数组,用来存放下标,每一次子序列更新都无需将该数组中的元素全部修改,只需要在修改下标的时候标记每个序列的个数,这样,找到最大子序列之后再依据标记输出数组相应个数的元素即可。