最大子段和问题描述
给定由 n 个整数(可能为负整数)组成的序列a1,a2,a3...an,求该数列中连续子段和最大!
例如:当(a1,a2,a3,a4,a5)=(-2,11,-4,13,-5,-2)时,最大字段和为 20 (11 + (-4) + 13);
以下例子都是以int data[6] = {-2,11,-4,13,-5,-2}; int n = 6;
算法一:对所有满足0<=i<=j<=n的(i,j)整数对进行迭代,对每个整数对,程序都要计算array[i...j]的总和,并检验该总和是否大于迄今为止的最大总和
这段代码简洁明了,便于理解,但是程序执行的速度很慢,时间复杂度为O(n^3)
int solveMaxCSSum1(){
int maxSum = 0; //记录最大子段和的变量
int tempSum; //记录最大子段和的临时变量
int i,j,k;
for(i=0;i<n;i++){
for(j=i;j<n;j++){
tempSum = 0; //每次从 i 加到 j 时,临时变量都必须归零
for(k=i;k<=j;k++){ //从第 i 个数依次累加到第 j 个数
tempSum += data[k];
if(maxSum < tempSum){
maxSum = tempSum;
}
}
}
}
return maxSum;
}
算法二:对于算法一有一个明显的缺点,大量的计算重复。大家可以注意到:
这段代码简洁明了,便于理解,相比算法一程序执行的速度较快,时间复杂度为O(n^2)
array[i...j]的总和与前面计算出的总和(array[i...j-1])密切相关
只需要在其基础上累加即可,无需大量重复计算!
int solveMaxCSSum2(){
int maxSum = 0; //记录最大子段和的变量
int tempSum; //记录最大子段和的临时变量
int i,j,k;
for(i=0;i<n;i++){
tempSum = 0; //每次 i 从一个新位置开始,临时变量都必须归零
for(j=i;j<n;j++){
tempSum += data[j]; //在之前的基础上直接进行累加
if(maxSum < tempSum){
maxSum = tempSum;
}
}
}
return maxSum;
}
算法三:可以采用分治算法求解,采用二分法进行二分,然后进行递归求解,分别求出左边连续子段和最大值,右边连续子段和最大值,
以及左边和右边连续子段和最大值之和,三者进行比较,从中选择一个最大值进行返回!(这个值即就是当前划分的小区间中最大值)
这段代码不太便于理解,但是程序相对于算法二执行的速度快,时间复杂度为O(n*logn)
int solveMaxCSSum3(int left,int right){
int maxSum = 0;
if(left == right) //如果序列长度为 1,直接求解
{
if(data[left] > 0){
maxSum = data[left];
}else{
maxSum = 0;
}
}else{
int center = (left + right) / 2; //二分法划分
int leftMaxSum = solveMaxCSSum3(left,center); //递归求解左半部分最大值
int rightMaxSum = solveMaxCSSum3(center + 1, right);//递归求解右半部分最大值
int leftMax = 0; //记录左边最大值
int leftMaxTemp = 0; //记录左边最大值的临时变量
for(int i = center; i >= left; i--)
{
leftMaxTemp += data[i];
if(leftMaxTemp > leftMax){
leftMax = leftMaxTemp; //左边最大值放在 leftMax
}
}
int rightMax = 0;
int rightMaxTemp = 0;
for(int j = center + 1; j <= right; j++)
{
rightMaxTemp += data[j];
if(rightMaxTemp > rightMax){
rightMax = rightMaxTemp; //右边最大值放在 rightMax
}
}
maxSum = leftMax + rightMax;//(左边最大值和右边最大值之和)计算第 3 种情况的最大子段和
//比较(左边最大值)和(右边最大值)以及(两边最大值之和)进行比较,从中选择一个最大值返回
if(maxSum < leftMaxSum){
maxSum = leftMaxSum;
}
if(maxSum < rightMaxSum){
maxSum = rightMaxSum;
}
}
return maxSum;
}
算法四:使用动态规划来求解 ,由data[]数组我们易知,当maxSumTemp > 0时,maxSumTemp = data[i] + maxSumTemp (越加越大),否则maxSumTemp = data[i](不然越加越小)
这段代码便于理解,但是程序相对于算法三执行的速度最快,时间复杂度为O(n)
int solveMaxCSSum4(){
int maxSum = 0;
int maxSumTemp = 0;
maxSum = maxSumTemp = data[0]; //初始化
for(int i=1;i<n;i++){
if(maxSumTemp > 0 ){ //最大值临时变量只有大于零,才可能越加越大
maxSumTemp += data[i];
}else{ // 最大值临时变量只有小于零,直接等于data[i],否则越加越小
maxSumTemp = data[i];
}
if(maxSumTemp > maxSum){ //判断赋值
maxSum = maxSumTemp;
}
}
return maxSum;
}