最大子序列和問題


一,問題描述

給定(可能有負數)整數a(1)、a(2)、……a(n),求 a(1)+a(2)+……+a(j)的最大值。為方便起見,若所有的整數為負數,則最大子序列和為0.

也就是:在一系列整數中,找出連續的若干個整數,這若干個整數之和 最大。

 

二,求解思路

下面介紹兩種思路,一種的時間復雜度為O(N^3),另一種為O(N)。這兩種方法分別類似於 在O(N)時間內求解 正數數組中 兩個數相加的 最大值   和 兩種方法求解 正數數組中 兩個數相減 的最大值

里面介紹的O(N^2)算法和 O(N)算法。都是采用了“貪心”的思想 忽略掉某些不需要判斷的元素,如本文中算法二:總是選擇,使當前序列之和變成負數的下一個元素作為新的起點。

因此,可以看出,最大子序列和問題 其實 與尋找“正整數數組中兩個數相減的最大值” 、“正整數數組中兩個數相加的最大值”等問題很相似。

算法一如下:

分別用兩個下標 i , j 標記某個子序列的起點和終點。然后,從 i 遍歷 到 j,求出[i,j]內所有元素的和,這個 和值 就是這一段子序列的和。

i belongs to [0, arr.length) , j belongs to [i, arr.length) 這樣,就代表了所有的子序列,再找出所有子序列和的最大值。

代碼如下:

 1     public static int maxSubSum1(int[] arr) {
 2         int maxSum = 0;
 3 
 4         for (int i = 0; i < arr.length; i++)
 5             for (int j = i; j < arr.length; j++) {
 6                 int thisSum = 0;
 7                 for (int k = i; k <= j; k++)
 8                     thisSum += arr[k];// 求解[i,j]這段子序列的和
 9                 if (thisSum > maxSum)
10                     maxSum = thisSum;
11             }
12         return maxSum;
13     }

 

算法二如下:

算法二基於下面兩個事實:

①任何負的 子序列都不可能是最大子序列和 的前綴

②當加上 下標 j 所在的元素 使得 當前序列的和變成負數時,根據①,可以從 j+1 處重新開始計算下一段子序列的和。

因為某段子序列到索引 j 位置時,它們的和是負的,意味着最大子序列不會 包含這一段子序列,那么從 j+1 開始,能不能找到一段更大的子序列。

代碼如下:

 1     public static int maxSubSum2(int[] arr) {
 2         int maxSum = 0;
 3         int thisSum = 0;
 4         for (int i = 0; i < arr.length; i++) {
 5             thisSum += arr[i];
 6             if (thisSum > maxSum)// thisSum在[0,maxSum]之間時不需要任何處理
 7                 maxSum = thisSum;
 8             else if (thisSum < 0)// 說明加上當前元素使得子序列為負數了,那么拋棄這段子序列(相當於thisSum賦值為0),從下一輪for開始
 9                 thisSum = 0;
10         }
11         return maxSum;
12     }

 

三,運行時間的比較

采用 這篇文章 中提到的隨機數生成算法 來隨機生成一個數組,然后比較上面兩個算法的運行時間。

機器環境如下:

OS:win7 64bit、RAM:6GB、CPU:Pentium(R)Dual-Core E5800@3.2GHz

時間比較如下:

數組大小        maxSubSum1運行時間(O(N))       maxSubSum2算法2運行時間(O(N^3))

100*10             0                                              95

200*10             0                                              647

300*10             0                                              2128

400*10             0                                              40246

 

這就是差距。。。。。。

 

完整程序代碼如下:

 1 public class MaxSequence {
 2 
 3     public static int maxSubSum1(int[] arr) {
 4         int maxSum = 0;
 5 
 6         for (int i = 0; i < arr.length; i++)
 7             for (int j = i; j < arr.length; j++) {
 8                 int thisSum = 0;
 9                 for (int k = i; k <= j; k++)
10                     thisSum += arr[k];// 求解[i,j]這段子序列的和
11                 if (thisSum > maxSum)
12                     maxSum = thisSum;
13             }
14         return maxSum;
15     }
16 
17     public static int maxSubSum2(int[] arr) {
18         int maxSum = 0;
19         int thisSum = 0;
20         for (int i = 0; i < arr.length; i++) {
21             thisSum += arr[i];
22             if (thisSum > maxSum)// thisSum在[0,maxSum]之間時不需要任何處理
23                 maxSum = thisSum;
24             else if (thisSum < 0)// 說明加上當前元素使得子序列為負數了,那么拋棄這段子序列(相當於thisSum賦值為0),從下一輪for開始
25                 thisSum = 0;
26         }
27         return maxSum;
28     }
29 
30     public static void main(String[] args) {
31         int[] arr = C2_2_8.randomArr(100*80);
32 
33         long start = System.currentTimeMillis();
34         int r = maxSubSum2(arr);
35         long end = System.currentTimeMillis();
36         System.out.println("maxValue=" + r + "  O(N)'s time:" + (end - start));
37 
38         long start2 = System.currentTimeMillis();
39         int r2 = maxSubSum1(arr);
40         long end2 = System.currentTimeMillis();
41         System.out.println("maxValue=" + r2 + "  O(N^3)'s time:"
42                 + (end2 - start2));
43 
44     }
45 }

 


免責聲明!

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



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