劍指offer:連續子數組的最大和(java)

題目:輸入一個整型數組,數組裏有正數也有負數。數組中一個或連續的多個整數組成一個子數組。求所有子數組的和的最大值。要求時間複雜度爲O(n)

      例如輸入的數組爲{1,-2,3,10,-4,7,2,-5},和最大的子數組爲{3,10,-4,7,2},因此輸出爲該子數組的和18。

     看到該題目,很多人都能想到最直觀的方法,即枚舉出數組的所有子數組並求出他們的和。一個長度爲n的數組,總共有n(n+1)/2個子數組。計算出所有的子數組的和,最快也需要O(n2)的時間。通常最直觀的方法不會是最優的方法,面試官將提示我們還有更快的方法。

解法一:舉例分析數組的規律

     我們試着從頭尾逐個累加示例數組中的每個數字。初始化和爲0.第一步加上第一個數字,此時和爲1.接下來第二步加上數字-2,和就編程了-1.第三步加上數字3.我們注意到由於此前累計的和爲-1,小於0,那如果用-1加3,得到的和爲2,比3本身還小。也就是說從第一個數字開始的子數組的和會小於從第三個數字開始的子數組的和。因此我們不用考慮從第一個子數組,之前累計的和也被拋棄。

    我們從第三個數字重新開始累加,此時得到的和爲3.接下來第四步加10,得到和爲13.第五步加上-4,和爲9.我們發現-4是一個負數,因此累加-4之後得到的和比原來的還小。因此我們要把之前得到的和13保存下來,它有可能是最大的子數組的和。第六步加上數字7,9加7的結果是16,此時和比之前最大的和13還要大,把最大的子數組的和由13更新爲16.第七步加上2,累加得到的和爲18,同時我們也要更新最大子數組的和。第八步加上最後一個數字-5,由於得到結果爲13,小於此前得到的最大和18,因此最終最大的子數組的和爲18,對應的子數組是{3,10,-4,7,2}。

 public Integer findGreatestSum(int[] arr){  
          
        if(arr.length ==0)  
            return null;   
        int greatest = 0x80000000;  
        int curSum = 0;  
        for(int i = 0;i<arr.length;i++){  
            if(curSum <= 0)  
                curSum = arr[i];  
            else  
                curSum += arr[i];  
            if(curSum >greatest)  
                greatest = curSum;  
        }  
        return greatest;  
    }  

解法二:應用動態規劃法

    我們還可以適用動態規劃的思想來分析這個問題。如果用函數f(i)表示以第i個數字結尾的子數組的最大和,那麼我們需要求出max[f(i)],其中0<=i<n。我們可以使用能夠下面的遞歸公示求f(i):


    這個公式的意義:當以第i-1個數字結尾的子數組中所有的數字的和小於0時,如果把這個負數與第i個數累加,得到的結果比第i個數字本身還要小,所以這種情況下以第i個數字結尾的子數組就是第i個數字本身。如果以第i-1個數字結尾的子數組中所有的數字的和大於0,與第i個數字累加就得到以第i個數字結尾的子數組中所有的數字的和。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章