(8)算法設計

一、算法設計

    1、問題描述:輸入具有n個浮點數的向量x,輸出是輸入向量的任何連續子向量中的最大和。

    有效解決方法:

    (1)分治算法:要解決規模爲n的問題,可遞歸得解決兩個規模近似爲n/2的子問題,然後對他們的答案進行合併以得到整個問題的答案。

    代碼如下,最大子向量要麼整個在a中,要麼整個在b中,要麼跨越a和b之間的邊界。跨越a和b 的邊界時,其最大子向量在a中的部分包含右邊界的最大子向量,在b中的部分包含左邊界的最大子向量。算法複雜度爲O(nlogn)。

float maxsum3(l, u)

    if (l > u)    return 0

    if (l == u )    return max(0, x[l])

    m = (l + u) / 2

    lmax = sum = 0

    for (i = m; i >= l; i--)

         sum += x[i]

         lmax = max (lmax, sum)

    rmax = sum = 0

    for i = (m, u]

         sum += x[i]

         rmax = max (rmax, sum)

    return max(lmax+rmax, maxsum(l, m), maxsum3(m+1, u))

    (2)一個O(n)複雜度的算法,從最左端(元素 x[0])開始,一直掃描到最右端(元素 x[n-1]),記下所碰到過的最大總和子數組。最大值初始爲0.假設已經解決了針對 x[0..i-1] 的問題,現在需要拓展到 x[i] 中。可以使用類似分治法中的道理,前 i 個元素中,最大總和子數組要麼在 i-1 個元素中(存儲在 maxsofar 中),要麼截止到位置 i(存儲在 maxendinghere中)。算法代碼更加簡短,但是運行起來是最快的,運行時間是O(n),已經是線性算法。源代碼如下:

float max_subvector5(float array[], int length)
{
    int i;
    float maxsofar = 0, maxendinghere = 0; 
    for(i = 0; i < length; i ++)
    {
        maxendinghere = (maxendinghere + x[i]) > 0 ? maxendinghere : 0;
        maxsofar = maxsofar > maxendinghere ? maxsofar : maxendinghere;
    }
    return maxsofar;
    
}

二、總結

    本章故事中的這些算法給出了幾個重要的算法設計技術:
    1、保存狀態,避免重複計算。通過使用一些空間來保存中間計算結果,我們避免了花時間來對其重複計算。
    2、將信息預處理到數據結構中。
    3、分治算法。
    4、掃描算法。與數組相關的問題經常可以通過思考“如何將x[0...i-1]的解擴展爲x[0...i]地解來解決。
    5、累積。
    6、下界。確定相匹配的下界。

三、習題

    1、習題10:假設我們要查找的是總和最接近0的子向量,而不是具有最大總和的子向量,則如何設計算法?若查找總和最接近某一個給定實數t的子向量呢?

    解答:初始化累積數組cum,使得cum[i] = x[0] + ... + x[i]。如果cum[l-1] = cum[u],那麼子向量x[l...u]之和就爲0.所以可以通過定位cum中最接近的兩個元素來找出和最接近零的子向量,可通過排序累積數組並比較相鄰元素間的大小從而得到結果。找最接近某一特定值的算法類似這樣。

   2、習題13:在最大子數組問題中,給定m*n的實數數組,我們需要求出矩形子數組的最大總和。該問題的複雜度如何?

    解答:可以在長度爲m的維度上使用平方複雜度的算法,而在長度爲n的維度上使用線性算法。可以在O(m^2*n)的時間複雜度內解決m*n問題。代碼如下所示:

float max_subarr(float **array, int row, int col)
{
    int i, j, k;
    float *vector, max = 0, maxsofar, maxendinghere;
    assert(row > 0 && col > 0);
    vector = (float *) malloc(col * sizeof(float));
    assert(vector != NULL);
    printf("the array :\n");
    for( i = 0; i < row; i ++)
    {
        memset(vector, 0, col * sizeof(float));//初始化爲0
        for( j = i; j < row; j ++)
        {
      //vector[k]的值爲行i至行j的第k列元素之和,把二維問題轉化爲一維問題。 
            for(k = 0; k < col; k ++)
                vector[k]  +=  array[j][k];//vector[k] = array[i][k] + array[i + 1][k] + ... + array[j][k], 
            maxsofar = vector[0];
            maxendinghere = 0;
            for(k = 0; k < col; k ++)
            {
                maxendinghere = (maxendinghere + vector[k]) > 0 ? (maxendinghere + vector[k]) : 0;
                maxsofar = maxsofar > maxendinghere ? maxsofar : maxendinghere;
            }
            
            max = max > maxsofar ? max : maxsofar;
            
        }
    }
    return max;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章