题目描述:
给定一个整型数组,数组有正数也有负数,现在要求数组中连续的数求和得到的最大值.例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止).
要求:
1.时间复杂度为O(n).
2.输出最大值,并输出获得最大值的子数组的开始下标与结束下标.
解法:
要求时间复杂度为O(n),暴力破解O(n^2)则不适合。这里考虑两种情况:
1.数组的成员全部为负数,那么能得到连续子数组最大和的子数组只能是该数组中值最大的负数。
2.数组的成员有正有负或者全部为正的情况。
事实上,如果我们只考虑枚举出全部子数组的话,就会遍历到许多多余的子数组。比如对于数组{6,-3,-2,7,-15,1,2,2},{-3,-2,7}就是一个多余的不需要考虑的子数组,我们要寻找的最大和子数组第一个数肯定不为负数,如果是负数,最大和子数组应该从下一个数开始寻找。好了,那现在如果把最大和子数组的前某一部分和看做第一个数的话,也就意味着最大和子数组的前部分的和也必须大于零。于是我们总结出了有正有负的数组的最大和子数组的特征,第一个数大于0且该子数组的任意前段数组的和大于零。
相对于下一个待加的数字Next而言,该数字前面的某个子数组的和SUM如果为负数,那么就不符合最大和子数组的特征,最大和子数组肯定不包含这一个子数组代表的序列,我们应该舍弃该序列,从Next重新开始寻找最大和连续子数组。
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
ArrayList<Integer> array = new ArrayList<Integer>();
while(sc.hasNext()){
array.add(sc.nextInt());
}
findMaxSubSum(array);
}
public static void findMaxSubSum(ArrayList<Integer> array){
int[] a = checkIfAllNegative(array);
//对应于第一种情况,遍历数组,判断是否全部由负数构成,如果是的话,则最大和子数组为该数字的最大值单个元素
if(a[0] < 0){
System.out.println("Max Sum is " + a[0] + " from index " + a[1] + " to " + a[1]);
return;
}
//对应于第二种情况
else{
//全局最大值,全局下标
int max = 0, maxStart = 0, maxEnd = 0;
//当前子串最大值,当前子串下标
int subMax = 0, subStart = 0, subEnd = 0;
for(int i = 0; i < array.size(); i++){
subMax += array.get(i);
if(subMax < 0){
//如果子串的和小于0,舍弃该子串,从下一个位置开始寻找最大和子数组
subStart = i+1;
subMax = 0;
}
else{
subEnd = i;
}
if(max < subMax){
//如果子串的和大于全局最大值,则保存新的全局最大值与下标
maxStart = subStart;
maxEnd = subEnd;
max = subMax;
}
}
System.out.println("Max Sum is " + max + " from index " + maxStart + " to " + maxEnd);
return;
}
}
public static int[] checkIfAllNegative(ArrayList<Integer> array){
int max = array.get(0);
int index = 0;
int[] a = new int[2];
for(int i = 1; i < array.size(); i++){
if(max < array.get(i)){
index = i;
max = array.get(i);
}
}
a[0] = max;
a[1] = index;
return a;
}
}