最大連續子數組和算法(動態規划解釋)


之前在其他博客看到了,但是算法的關鍵部分完全看不懂為什么要這么做,直到最近上算法課,才終於知道到底怎么來的。

問題描述:

  給出一個數組,求其最大連續子數組和

  例:數組{1,2,3,4,-5,10,-1,-1}的最大連續子數組和是子數組{1,2,3,4,-5,10}的和15

算法過程:

  這個算法能從零直接想出來的人是真的厲害,我並不可以,所以我直接描述一下這個算法是怎么算的,而不描述怎么想到的了

  首先我們把原來數組記做a,然后最關鍵的一步,我們需要一個等長的數組b,b[j]的含義是以下一系列和中的最大值

a[0] + a[1] + a[2] + a[3] + … + a[j]
       a[1] + a[2] + a[3] + … + a[j]
              a[2] + a[3] + … + a[j]
                     a[3] + … + a[j]
                            ……
                                a[j]

那么顯然可以知道的是,b數組中的最大值,就是我們想要的a的最大連續子數組和。

接下來就是要得到數組b,初始化的話,b[0]應該為0和a[0]之中的較大者,下面探討b[j]和b[j+1]之間的關系:

  b[j+1]只有兩種取法,第一種是b[j]+a[j+1],注意b[j]本身就是最大值,所以不用再去考慮b[j]內部的情況了,第二種是a[j+1],所以

  b[j+1] = max{ b[j]+a[j+1], a[j+1] }

OK,到此這個算法其實就算完成了,下面是直接根據這個思路打的代碼:

#include <stdio.h>
#include <stdlib.h>

int main() {
    int a[] = {1,2,3,4,-5,10,-1,-1};  // 原數組
    int* b = (int*)malloc(sizeof(a)); // 數組b,和原數組等長

    // 初始化
    b[0]= a[0] > 0 ? a[0] : 0;

    // 遍歷構造,注意i的邊界
    int length = sizeof(a) / sizeof(int); // 數組長
    for (int i = 0; i < length - 1; i++) {
        b[i+1] = b[i] + a[i+1] > a[i+1] ? b[i] + a[i+1] : a[i+1];
    }

    // 然后找出b中的最大值
    int max = b[0];
    for (int i = 1; i < length; i++)
        if (b[i] > max)
            max = b[i];

    printf("max=%i\n", max);
    return 0;
}

  然后導致我一直看不懂的地方來了,對上面這段代碼進行編程上的優化,優化主要有兩個地方,

  首先在上面的分析中,b[n+1]只和當前遍歷到的a[n+1]和前一個b[n]直接相關,所以其實並不需要保存整個數組b,換用一個變量就可以了,其次是最大值,也是可以一遍遍歷一邊改的

  於是就有了目前網絡上流傳最多的以下這種代碼:

#include <stdio.h>
#include <stdlib.h>

int main() {
    int a[] = {1,2,3,4,-5,10,-1,-1};  // 原數組
    int max = 0;
    int b = 0;

    int length = sizeof(a) / sizeof(int); // 長度
    for (int i = 0; i < length; i++) {
        b = b + a[i] > a[i] ? b + a[i] : a[i];
        max = max > b ? max : b;
    }

    printf("max=%i\n", max);
    return 0;
}

顯然這個算法是o(n)時間復雜度的,講真最近學動態規划基本o(n^3)起步。動態規划兩個基本要素,首先最優子結構性質,全局最大值基於n個子問題b的最優解,而且可以看到b[j+1]是基於b[j]給出的,也就是一個問題是基於他的子問題的最優解來解決的,其次顯然子問題是有交叉的,求解b[j]需要b[j-1],遞歸一下就需要b[j-2],由此就出現了交叉。

PS:LeetCode上題號53 最大子序和就是這個問題,但是貌似子數組長度不為0,所以初始化會有一點變化。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM