求連續子陣列和的最大值的變種問題

2021-06-26 22:39:10 字數 2019 閱讀 5756

求連續子陣列和的最大值,是乙個很經典的問題,網上有很多文章來介紹這個問題,我們先簡要介紹一下這個問題的動態規劃解法。

對於乙個輸入陣列a[n],我們用res表示該陣列連續子陣列和的最大值,用sum[i]表示前i個元素中,包含第i個元素且和最大的連續子陣列的和,這樣我們可以從頭到尾遍歷陣列,執行以下公式:

sum[i + 1] = max (a[i + 1], sum[i])

res= max (res, sum[i + 1])

對於sum陣列,我們在乙個時刻只會使用乙個值,可以簡化為乙個數,具體**如下所示: 

int solve(int a) 

int sum = a[0], res = a[0];

for (int i = 1; i < a.length; i++)

sum += a[i];

res = math.max(sum, res);

}return res;

}

但是,這個問題並不是本文所討論的重點,我們要討論的是該問題的兩個變種問題。

變種一:求連續子陣列和的絕對值的最小值

這個問題乍看一下,不是也能用動態規劃的思想來解決嗎?解法如下:

用res表示該陣列連續子陣列和的絕對值的最小值,用sum[i]表示前i個元素中,包含第i個元素且和的絕對值最小的連續子陣列的和,這樣依然可以從頭到尾遍歷陣列,執行以下公式:

sum[i + 1] = sum[i] * a[i + 1] >= 0 ? a[i + 1] : sum[i] + a[i + 1]

res = min (res, sum[i + 1])

這個方法的思想就是,如果sum[i]和a[i + 1]正負符號不同,則a[i + 1]加上sum[i]會有可能更接近0,從而使res有可能會更小;否則我們就直接捨棄sum[i],直接令sum[i + 1]等於a[i + 1],因為加上sum[i]會使sum[i + 1]更加偏離0。

上面方法介紹完了,看上去很有道理啊,但是非常不幸的是,這個方法是錯誤的。比如說,對於-5,-5,10構成的陣列,按這種方法得到的結果為5,但實際上的結果為0。這是因為這個方法採用的是貪心的策略,並沒有滿足動態規劃的最優子結構的條件,即sum[i + 1]為最優解並不能保證它的子問題sum[i]也是最優解。

既然我們不能使用動態規劃來求解了,而暴力法需要o(n^2)的時間複雜度,那有沒有好一些的方法呢?

我們試著求陣列a[n]的字首和陣列b[n + 1],即

b[0] = 0

b[1] = a[0] + b[0]

b[2] = a[1] + b[1]

b[n] = a[n - 1] + b[n - 1]

可以看出,a[i] + a[i + 1] + ... + a[i + k] = b[i + k + 1] - b[i],這樣我們可以把求陣列a的連續子陣列和的絕對值的最小值的問題,轉化為求字首陣列b中兩兩之差的絕對值最小值,然後我們對陣列b進行排序,然後比較相鄰兩個元素差的絕對值,得到的最小值便是陣列a的連續子陣列和的絕對值的最小值。時間複雜度方面,陣列a轉換為陣列b需要o(n)的時間,陣列b排序需要o(nlog(n))的時間,比較陣列b相鄰兩個元素差的絕對值需要o(n)的時間,因此整體的時間複雜度為o(nlog(n))。

變種二:求環形陣列連續子陣列和的最大值

環形陣列相比於非環形陣列,它多了一些可能的情況,即非環形陣列中前面一小部分和後面一小部分組成的連續子陣列,而我們用原來的方法,是無法計算這種情況的。

對於環形陣列a[n],我們用sum(i, j)表示從下標i到j - 1的連續子陣列和,則對於連續子陣列和的最大值為sum(0, i) + sum(j, n)的情況(其中i < j),由於陣列a的總和是固定值,我們可以將問題進行轉換,用原來的方法來求該連續子陣列和的最小值sum(i, j),然後拿總和減去這個最小值,就能得到這種情況的最大值。這樣我們分別用原來的方法,分別計算一次連續子陣列和的最大值max和最小值min,以及陣列所有元素之和total,這樣環形陣列連續子陣列和的最大值就為max和total - min中的較大者。這種方法的時間複雜度依然為o(n)。

求最大連續子陣列和的最大值

題目描述 給定乙個陣列a 0,n 1 求a的連續子陣列,使得該子陣列的和最大。eg 1,2,3,10,4,7,2,5的最大子陣列為3,10,4,7,2 演算法分析 記s i 為以a i 結尾的陣列中和最大的子陣列,則s i 1 max s i a i 1 a i 1 s 0 a 0 遍歷i 0 i ...

求連續子串行的最大值

問題描述 有一串數字 可正可負的int,放在陣列num裡 要求找到起始位置start和終止位置end,使得從start位置到end位置的所有數字之和最大,返回這個最大值max。演算法思想 使用動態規劃。設 f x 為以 a x 終止且包含 a x 的最大序列的和,有 f 1 a 1 f x 1 f ...

java 求出連續子陣列和為最大值的子陣列資訊

public static void main string args int max arr 0 連續n項相加值最大的子陣列和 int maxstartindex 0 連續n項相加值最大的子陣列起始索引 int maxendindex 0 連續n項相加值最大的子陣列終止索引 int sum arr...