首页 > 代码库 > 关于求最大子段和的几种算法

关于求最大子段和的几种算法

一、比较朴素的算法

算法思想:我们确定每个子段和开始的位置,分别为第一个,第二个,第三个......第N个,然后计算从这个位置开始到这个位置之后的每个位置的子段和,更新记录最大的子段和。

时间复杂度:O(n^2)

算法实现(Java):

package com.Third;

import java.util.*;
public class Main3{
    public static int maxSum2(int a[]){
        int nowSum=0;//用于记录从指定位置到当前位置累加的值
        int maxSum=0;//用于记录当前最大的子段和
        for(int i=0;i<a.length;i++){
            nowSum=0;
            for(int j=i;j<a.length;j++){
                nowSum=nowSum+a[j];
                if(nowSum>maxSum){//更新最大子段和
                    maxSum=nowSum;
                }
            }
        }
        
        return maxSum;
    }
    public static void main(String[] args) {
        int a[]={4,-3,5,-2,-1,2,6,-2};
        System.out.println(maxSum2(a));
    }
}

二、分治法(递归)

算法思想:

通过分治的思想求最大子段和,将数组分平均分为两个部分,则最大子段和会存在于三种情况下:
1.最大子段和出现在左端
2.最大子段和出现在右端
3.最大子段和横跨在左右段  通过比较大小得到最大子段和

时间复杂度:O(nlogn)

算法实现(Java):

package com.Third;
/*
 * 通过分治的思想求最大子段和,将数组分平均分为两个部分,则最大子段和会存在于三种情况下:
 * 1.最大子段和出现在左端
 * 2.最大子段和出现在右端
 * 3.最大子段和横跨在左右段
 */
public class Main {
    public static int maxSumRec(int []a,int start,int end){
        if(start==end){//这里是递归的函数出口
            if(a[start]>0){
                return a[start];
            }else{
                return 0;
            }
        }
        int maxLeftSumRec=maxSumRec(a,start,(start+end)/2);//计算左半边的最大字段和
        int maxRightSumRec=maxSumRec(a,((start+end)/2)+1,end);//计算右半边最大子段和
        //计算最大子段和在中间的情况
        int leftMaxMark=0;
        int leftSum=0;        
        for(int i=(start+end)/2;i>=0;i--){
            leftSum=leftSum+a[i];
            if(leftSum>leftMaxMark){
                leftMaxMark=leftSum;
            }
        }
        int rightMaxMark=0;
        int rightSum=0;
        for(int i=((start+end)/2)+1;i<=end;i++){
            rightSum=rightSum+a[i];
            if(rightSum>rightMaxMark){
                rightMaxMark=rightSum;
            }
        }
        int maxMidSumRec=leftMaxMark+rightMaxMark;
        //比较三种情况那种情况是最大的子段和
        int maxSum=maxLeftSumRec;
        if(maxSum<maxRightSumRec){
            maxSum=maxRightSumRec;
        }
        if(maxMidSumRec>maxSum){
            maxSum=maxMidSumRec;
        }
        return maxSum;
    }
    public static void main(String[] args) {
        int a[]={4,-3,5,-2,-1,2,6,-2};
        System.out.println(maxSumRec(a,0,7));
    }   
}

三、动态规划算法

算法思想:

运用了动态规划的思想来解决最大子段和问题:
通过遍历累加这个数组元素,定时的更新最大子段和,
如果当前累加数为负数,直接舍弃,重置为0,然后接着遍历累加。

时间复杂度:O(n)

算法实现(Java):

package com.Third;
/*
 * 这是运用了动态规划的思想来解决最大子段和问题:
 * 通过遍历累加这个数组元素,定时的更新最大子段和,
 * 如果当前累加数为负数,直接舍弃,重置为0,然后接着遍历累加。
 */
public class Main1{    
   public static int maxSubSum1(int []a){
       int maxSum=0; int nowSum=0;
       for(int i=0;i<a.length;i++){
           nowSum=nowSum+a[i];
           if(nowSum>maxSum){//更新最大子段和
               maxSum=nowSum;
           }
           if(nowSum<0){//当当前累加和为负数时舍弃,重置为0
               nowSum=0;
           }
       }   
       return maxSum;
   }
   public static void main(String[] args) {
       int a[]={4,-3,5,-2,-1,2,6,-2};
       System.out.println(maxSubSum1(a));
   }
}

 

关于求最大子段和的几种算法