最大子數組的和

最大子數組的和

    在給定的一個數組中,找出連續的一部分數組,使其中的元素和最大。例如輸入1,-2,5,3,-3,7,-2,-1,輸出的最大子數組和爲12

    如果什麼都不考慮,用最直接的辦法來求解,即三重for循環來暴力求結果,該算法的時間複雜度爲O(n^3)代碼如下:

//本段代碼引自編程之美
int MaxSum(int* A, int n)
{
 int maximum = -INF; 
int sum=0;   
for(int i = 0; i < n; i++)
{
 for(int j = i; j < n; j++)
{
  for(int k = i; k <= j; k++)
  {
   sum += A[k];
  }
 if(sum > maximum)
 maximum = sum;
 sum=0;
}
 }
 return maximum;
} 

    如果不需要輸出最大子數組,只需要最大子數組的和的情況下,有一個時間複雜度只有O(n)的算法,下面是C語言的實現代碼:

void max_sub_array(int count, int* a)
{
    int sum = a[0], t = 0;
    for (int i = 0; i < count; i++)
    {
        if (t < 0)
        {
            t = a[i];
        }
        else
        {
            t += a[i];
        }
        if (sum < t)
            sum = t;
    }
    printf("The max is %d\n", sum);
}
void main()
{
    int count, *p;
    printf("please input the count :");
    scanf_s("%d", &count);
    p = (int *)malloc(count * 2);
    printf("\nplease input the number to be sorted : \n");
    for (int i = 0; i < count; i++)
    {
        scanf_s("%d", p+i);
    }
    max_sub_array(count, p);
    system("pause");
}

    上面的這種算法,將整個數組遍歷一遍,sum用來記錄當前最大和,t用來記錄當前正在被運算的子數組的和。如果發現t<0,則將之前算的那些子數組拋棄,從當前的a[i]開始,因爲之前算的子數組和爲負數,再進行下去就沒有意義。如果t>0或t=0,則繼續正在計算的子數組。最後判斷當前子數組最大和(t)與當前最大和(sum)的大小,直到整個數組遍歷完成。

    使用分治策略來解決問題的話,假設我們原數組爲A[low,high],先將其分解成兩個儘可能規模相同的子數組A[low,mid]和A[mid+1,high]。則原數組的任何連續的子數組A[i,j]有下面三種情況:

  • 完全在子數組A[low,mid]中,即low<=i<=j<=mid。
  • 完全在子數組A{mid+1,high]中,即mid+1<=i<=j<=high。
  • 跨越在了兩個子數組之間,low<=i<=mid<=j<=high。

    因此我們只需要找出這三者並選取其中的最大者即可,算法的時間複雜度爲O(n*lg(n))。下面是C語言的實現:

int max_sub_array(int from, int to, int* a)
{
    int max = 0;
    int left_max, right_max, mid_max;
    int mid_to_left_max = 0, mid_to_right_max = 0;
    int mid_to_left_sum = 0, mid_to_right_sum = 0;
    int mid = (to + from) / 2;

    if (from == to)
    {
        if (a[from] > 0)
            return a[from];
        else
            return 0;
    }

    //對問題進行分解,左邊和右邊分開求解最大和
    left_max = max_sub_array(from, mid, a);
    right_max = max_sub_array(mid+1, to, a);

    //對橫跨中間的最大和進行處理
    for (int i = mid; i >= from;i--)
    {
        mid_to_left_sum += a[i];
        if (mid_to_left_max < mid_to_left_sum)
            mid_to_left_max = mid_to_left_sum;
    }
    for (int i = mid + 1; i <= to; i++)
    {
        mid_to_right_sum += a[i];
        if (mid_to_right_max < mid_to_right_sum)
            mid_to_right_max = mid_to_right_sum;
    }

    //將求解出的三種情況下的最大和作比較,取最大的返回
    mid_max = mid_to_left_max + mid_to_right_max;
    max = left_max;
    if (max < right_max)
        max = right_max;
    if (max < mid_max)
        max = mid_max;
    return max;
}
void main()
{
    int count, *p;
    printf("please input the count :");
    scanf_s("%d", &count);
    p = (int *)malloc(count * 2);
    printf("\nplease input the number to be sorted : \n");
    for (int i = 0; i < count; i++)
    {
        scanf_s("%d", p+i);
    }
    printf("The max is : %d.\n", max_sub_array(0, count - 1, p));
    system("pause");
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章