HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1)
/*
动态规划:
令f(i)表示索引从0到i这段区间中的和的最大值, 对应代码中的currMax
递推关系
f(i) = f(i-1) + array[i] if f(i-1)>0
f(i) = array[i] if f(i-1)<=0 or i==0
*/
/*
连续子数组
维护子数组的左右边界
*/
public class Solution {
public int FindGreatestSumOfSubArray(int[] array) {
int max = Integer.MIN_VALUE;
int sum=0;
for(int i=0; i<array.length; i++){
//update
sum += array[i];
max = Math.max(max, sum);
//update
if(sum <=0)
sum=0;
}
return max;
}
}
public class Solution {
public int FindGreatestSumOfSubArray(int[] array) {
int currSum=0, maxSum=Integer.MIN_VALUE;
for(int i=0; i<array.length; i++){
//这句体现了“选还是不选”sum(0...i-1); 同时也是是否更新左边界
currSum = Math.max(currSum + array[i], array[i]);
//是否更新最大值
maxSum = Math.max(currSum, maxSum);
}
return maxSum;
}
}
public class Solution {
public int FindGreatestSumOfSubArray(int[] array) {
int currSum=0, maxSum=Integer.MIN_VALUE;
for(int i=0; i<array.length; i++){
currSum = currSum + array[i];//考虑当前项之后的和
maxSum = currSum > maxSum? currSum : maxSum;//每次都更新最大值
if(currSum<=0)//是否需要更新左边界
currSum=0;//更新左边界就是令currSum=0
}
return maxSum;
}
}
public class Solution {
public int FindGreatestSumOfSubArray(int[] array) {
/*
什么时候更新子数组的左边界?
当当前子数组的元素和<=0时,子数组右边界的下一个元素作为子数组的新左边界
*/
return Core(array, 0, 0, Integer.MIN_VALUE);
}
public int Core(int[] arr, int index, int currSum, int maxSum){
//base case
if(index == arr.length)
return maxSum;
//
if(currSum+arr[index]<=0)
//这里注意不要把currSum赋成arr[index+1]了,
//currSum只跟0..index有关,跟index+1无关
//令currSum=0是更新左边界的毕竟操作
return Core(arr, index+1, 0, currSum+arr[index] > maxSum? currSum+arr[index]:maxSum);
else
return Core(arr, index+1, currSum+arr[index], currSum+arr[index] > maxSum? currSum+arr[index]:maxSum);
}
}
public class Solution {
public int FindGreatestSumOfSubArray(int[] array) {
/*
连续求了n个数的和, 如果这n个数的和小于等于0, 那么把第n+1个数赋给和. 因为连续的n+1数的和小于等于第n+1个数
如果这n+1个数的和大于0, 那么把第n+1个数加到和上,直到遍历完数组或者和小于等于零才会重置和
注意一点: 前面说"如果这n个数的和小于等于0", 为什么不限制为小于0,而是限制为小于等于0, 这是为了处理array[0]用的, sum初始值是0, 所以需要把array[0]赋值给sum
注意一点: 这个思路没有讨论array[i]值的大小, 只通过观察sum的值进行状态的改变
注意一点: sum是array[i]之前的连续n项和, 也就是根据sum的大小, 决定array[i]是加到sum上还是直接赋值给sum
注意一点: 需要设置一个变量记录当前的最大值, 因为sum并不代表当前的最大值, 只是尽力维持连续n项和大于0
*/
int sum = 0, currMax=Integer.MIN_VALUE;
for(int i=0; i<array.length; i++){
if(sum <= 0)
sum = array[i];
else //sum>0
sum += array[i];
if(sum > currMax)
currMax = sum;
}
return currMax;
}
}
public class Solution {
public int FindGreatestSumOfSubArray(int[] array) {
/*
动态规划:
令f(i)表示索引从0到i这段区间中的和的最大值
递推关系
f(i) = f(i-1) + array[i] if f(i-1)>0
f(i) = array[i] if f(i-1)<=0 or i==0
*/
int sum=0, max=Integer.MIN_VALUE;
for(int i=0; i<array.length; i++){
sum = Math.max(sum+array[i], array[i]); // 加sum与不加sum, 体现了动态规划的思想
max = Math.max(sum, max);
}
return max;
}
}
public class Solution {
public int FindGreatestSumOfSubArray(int[] array) {
/*
动态规划:
令f(i)表示索引从0到i这段区间中的和的最大值
递推关系
f(i) = f(i-1) + array[i] if f(i-1)>0
f(i) = array[i] if f(i-1)<=0 or i==0
*/
return Core(array, 0, 0, Integer.MIN_VALUE);
}
public int Core(int[] array, int index, int sum, int max){
//recursion finish
if(index==array.length)
return max;
//
int currMax;
if(index==0){
currMax=Core(array, index+1, array[index], array[index]); //注意区分index++和index+1, index++会改变index的值, index+1不会改变index的值
}
else{ //index>0
if(sum>0)
currMax=Core(array, index+1, sum+array[index], sum+array[index]>max?sum+array[index]:max);
else // sum<=0
currMax=Core(array, index+1, array[index], array[index]>max?array[index]:max);
}
return currMax;
}
}