1. 程式人生 > >演算法之求最大連續子陣列和

演算法之求最大連續子陣列和

假設給定一陣列{1,4,2,-3,-1,2,5,6,-8,9},我們要求的是最大的連續子序列的和,如果採用暴力破解法的話,那就是遍歷所有的連續子序列了,時間複雜度就是O(N^3)程式碼如下:
private int max = Integer.MIN_VALUE;
public int maxSubArray(int[] nums) {
int sum;
for (int i = 0; i < nums.length; i++) {// 子序列左端點
for (int j = i; j < nums.length; j++) {// 子序列右端點
sum = 0;
for (int k = i; k <= j; k++) {//暴力計算
sum += nums[k];
}
if (sum > max) {
max = sum;
}
}
}
return max;
}

那麼我們現在來考慮另外一種解法,我們先來考慮一個簡單的陣列
{2,4,3,5,7}
這個陣列的最大和肯定是整個陣列,那麼考慮一下包含負數的情況
{2,3,4,-9,5,6,7},也就是如下
在這裡插入圖片描述
我們先不考慮那麼多,我的整體思想就是,最開始sumax=sum=0,用一個指標i往前走,每走一個sum += a[i],然後比較
If sum > sumax:
sumax = sum
如果陣列全是正數的話,這樣是沒有問題的,但是如果陣列中出現了負數的話,比如上面陣列中間出現了一個-9,我們來分析:
當走到4這個位置時,sum = 2 + 3 + 4 = 9 > 5(sumax) ==> sumax = 9
當走到-9這個位置時 sum = 2 + 3 + 4 - 9 = 0 < 9(sumax) ==>sumx不變依然是9
此時的最大子序列為sumax = {2,3,4},因為後面還有子序列{5,6,7},它的和是大於9的
所以最終的最大子序列可能是{5,6,7}或者{2,3,4,-9,5,6,7},而又因為{2,3,4,-9}這部分是0,所以它們和是一樣的,所以我選擇{5,6,7}這個子序列,最開始的最大子序列是sumax = {2,3,4},因為中間是個-9,由於必須要連續,所以我的最大子序列必須得重置,從{5,6,7}中的5開始掃描,所以重置sum為a[i],即5
If sum <= 0:
sum = a[i]
如果中間不是-9的話假如是-10的話,那就是滿足sum < 0 的情況
最終sum = 5 + 6 + 7 > 9

最終程式碼如下:
public int maxSubArray(int[] nums) {// 動態規劃法
int sumax=nums[0];
int sum=nums[0];
for(int i=1;i<nums.length;i++) {
if(sum>0)sum+=nums[i];
else sum=nums[i];
if(sumax<sum)sumax=sum;
}
return sumax;
}

總結:
可以用一個累計和sum表示一些連續範圍的數,如果它大於sum_max,那就更新sum_max,當然這個連續範圍的數最開始,你分析的時候,可以從頭開始分析,但是最終的連續範圍的數可能不是從頭開始的,假如它是從某個下標開始到另外一個下標這個範圍,那麼你就需要將sum更新為這個下標的數,,從這個下標開始掃描,累加,先從一般情況分析起,,比如全是正的,然後變為特殊情況中間加了個負數