题目描述
HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1)
题目分析
记下标0到i的子向量最大和为ans[i],subRight[i]为以下标为i的元素结尾的所有子向量最大和,可以很容易得到,ans[i] = max(ans[i-1],subRight[i]),因为ans[i-1]由所有不包含array[i]的元素的子向量计算得出,subRight[i]由所有包含array[i]的元素的子向量计算得出。
那么题目的目标就是算出ans[array.length-1],怎么算a[i]?利用ans[i] = max(ans[i-1],subRight[i])即可,那么怎么算出subRight[i],首先subRight[0]一定是array[0],其他情况可以这样得出:如果subRight[i-1]>0,加上array[i]就可以,如果subRight[[i-1]<=0, 要得到最大的,还不如array[i]自己一个组成一个子向量。
由此可以在一次遍历得出答案,时间复杂度o(n)
代码实现
//子向量最大和ans[i]可以由Max(ans[i-1],以array[i]结尾的所有子向量最大和) 计算得出
public int FindGreatestSumOfSubArray(int[] array) {
if(array == null){
return 0;
}
int[] subRight = new int[array.length]; //这个数组的意义是 subRight[i] 为以array[i]结尾的所以子向量的最大和
for (int i = 0; i < subRight.length; i++) {
subRight[i] = 0; //初始化
}
int ans = Integer.MIN_VALUE;
for (int i = 0; i < array.length; i++) {
if(i == 0) //一开始先用array[0] 作为subRight[0]
subRight[i] = array[i];
else
subRight[i] = subRight[i-1]>0?subRight[i-1]+array[i]:array[i]; //不是开始,如果以左边元素结尾的子向量最大和大于0
// 则用左边结尾的子向量最大和加当前的值作为这里结尾的最大子向量最大和
//否则自己一个元素作为一个子向量
ans = Math.max(ans,subRight[i]); //与上一次得到的ans比较,相当于ans[i] = max(ans[i-1],subRight[i])
}
return ans;
}