1. 程式人生 > >c實現 求一個數組中最大子序列的和 (兩種方法)

c實現 求一個數組中最大子序列的和 (兩種方法)

||_ 題目描述

這裡寫圖片描述

||_ 分析
本題的核心是計算出一個序列的所有子序列中元素和為最大時的值,不要求輸出對應的子序列是什麼,而只要求輸出和的最大值是多少

  • 法一:
    我們把序列分成兩半(左邊和右邊),那麼和最大的序列要麼出現在左邊序列,要麼出現在右邊序列,要麼橫跨左右兩邊。而左邊序列又可以分成兩半,以此類推;右邊序列也一樣。由此,便可分而治之了。

    下面是程式碼:

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)