關於求最大子段和的幾種算法


一、比較朴素的算法

算法思想:我們確定每個子段和開始的位置,分別為第一個,第二個,第三個......第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));
   }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM