c實現 求一個數組中最大子序列的和 (兩種方法)
阿新 • • 發佈:2019-02-05
||_ 題目描述
||_ 分析
本題的核心是計算出一個序列的所有子序列中元素和為最大時的值,不要求輸出對應的子序列是什麼,而只要求輸出和的最大值是多少。
法一:
我們把序列分成兩半(左邊和右邊),那麼和最大的序列要麼出現在左邊序列,要麼出現在右邊序列,要麼橫跨左右兩邊。而左邊序列又可以分成兩半,以此類推;右邊序列也一樣。由此,便可分而治之了。下面是程式碼:
int maxSubArray(int* nums, int numsSize) {
return findMax(nums,0,numsSize-1);
}
int findMax(int* nums,int left,int right){
if(left==right)
return nums[left];
int mid=left+(right-left)/2;
int lmax=findMax(nums,left,mid);
int rmax=findMax(nums,mid+1,right);
int lpart=nums[mid];
int rpart=0;
int temp=0;
for(int i=mid;i>=left;i--){
temp+=nums[i];
if (temp>lpart)
lpart=temp;
}
temp=0;
for(int i=mid+1;i<=right;i++){
temp+=nums[i];
if(temp>rpart)
rpart=temp;
}
return lmax>rmax?lmax>(lpart+rpart)?lmax:(lpart+rpart):rmax>(lpart+rpart)?rmax:(lpart+rpart);
}
那複雜度怎麼樣呢?
T(n)=2T(n/2)+O(n);
由Master Theorem可得,計算的複雜度為O(nlogn)
法二:
我們要明白三點,
``
I、最大子序列的開始可以是陣列中的任意一個元素。所以我們可以通過一次遍歷就肯定經過過最大子序列的開始位置。
``
II、最大子序列的結尾是什麼位置呢?我們可以不管,因為我們只需要輸出值就好。只要用一個temp變數一直儲存所有已遍歷情況中的最大值就好。
``
III、簡化計算的核心:我們並不需要遍歷所有完子序列,如(-2,1,2,-4,5)和(1,2,-4,5)序列,因為-2+1<1,後者的結果總會比前者的大,那麼我們便可直接排除前者,而只遍歷後者了。可能說得有點繞,直接看程式碼吧:
int maxSubArray(int* nums, int numsSize) {
int i=0;
int suma=nums[0];
int sumb=0;
int max=nums[0];
for(i=1;i<numsSize;i++){
sumb += nums[i];
suma += nums[i];
if(suma>max)
max=suma;
if(sumb>max)
max=sumb;
if(suma<=sumb)
suma=0;
else
sumb=0;
}
return max;
}
那複雜度怎麼樣呢?
我們可以很直觀得看到,只有一個for迴圈,所以複雜度為O(n)