leetcode 410 分割陣列的最大值

2021-10-08 12:31:02 字數 3350 閱讀 1921

410. 分割陣列的最大值

給定乙個非負整數陣列和乙個整數 m,你需要將這個陣列分成 m 個非空的連續子陣列。設計乙個演算法使得這 m 個子陣列各自和的最大值最小。

注意:陣列長度 n 滿足以下條件:

1 ≤ n ≤ 1000

1 ≤ m ≤ min(50, n)

示例:輸入:

nums = [7,2,5,10,8]

m = 2

輸出:18

解釋:一共有四種方法將nums分割為2個子陣列。

其中最好的方式是將其分為[7,2,5] 和 [10,8],

因為此時這兩個子陣列各自的和的最大值為18,在所有情況中最小。

這道題的題目也沒搞很明白,n長度的陣列,分為m個組,計算每個組的和,找到當前分法的每個組的和的最大值。在多種分割方法中,選取一種最大值最小的分法,返回分的組數m。

實屬不會,哎,索性還是偷官方的題解吧。

在下筆之前需要考慮下這些問題,

假如有m個分割陣列,我們應該分割在哪乙個位置。

後面的分割位置與前面的分割位置息息相關,並且要保證分出m個陣列。

在計算一種分割方案的時候,我們怎麼才能保證,這個方案的最大子段和是所有m分割方案裡面最小的。

題解一使用的是動態規劃:

dp[i][j] 表示將陣列的前 i 個數分割為 j 段所能得到的最大連續子陣列和的最小值。動態規劃的引數含義設定也是一門藝術,偷不會。接下來就是動態轉移方程:

由於動態規劃是乙個數乙個數來考慮進行分割的,所以當前 i 個數中[0…k…i]是有多少個分成了 j - 1段。然後最後一段是由[k…i]組成的,所以需要列舉k.。之後就是確定最大子段和的最小值問題,我們現在對 dp[i][j]相當於是分成了兩端。

之前的一段 [0, k],其中 k < i, 之後的一段就是[k, i], 在確定前 i 個數能夠取到的最小值的時候,dp[k][j-i]表示前 j -1段能夠取得最小值。 之後得[k, i]是最後一段,所以最後一段得值就是 sum[k, i],然後我們對兩者進行比較,就能得出 dp[i][j]取得最小值應該是哪個。

d p[

i][j

]=mi

n;k∈

[0,i

−1

]dp[i][j] = min\; k∈[0,i-1]

dp[i][

j]=m

in;k

∈[0,

i−1]

對於狀態 dp[i][j],由於我們不能分出空的子陣列,因此合法的狀態必須有 i ≥ j。對於不合法(i此外,我們還需要將 dp[0][0] 的值初始化為 0,在上述的狀態轉移方程中,當 j=1 時,唯一的可能性就是前 i 個數被分成了一段。如果列舉的 k=0,那麼就代表著這種情況;如果 k =0,對應的狀態 dp[k][0]是乙個不合法的狀態,無法進行轉移。因此我們需要令 dp[0][0] = 0。

class

solution

:def

splitarray

(self, nums: list[

int]

, m:

int)

->

int:

nums =[0

]+ nums

n =len(nums)

sums =[0

]for num in nums[1:

]:#計算連續的子段和-1

]+num)

dp =[[

float

('inf')]

*(m+1)

for _ in

range

(n)]

#構建乙個dp列表

dp[0]

[0]=

0#dp動態轉移方程, j的取值範圍取分段次數和i的個數中的最小值,因為有可能i的個數小於分段數

for i in

range(1

, n)

:for j in

range(1

,min

(i+1

, m+1)

):for k in

range

(i):

dp[i]

[j]=

min(dp[i]

[j],

max(dp[k]

[j-1

], sums[i]

- sums[k]))

return dp[-1

][-1

]

二分查詢:

本題中,我們注意到:當我們選定乙個值 x,我們可以線性地驗證是否存在一種分割方案,滿足其最大分割子陣列和不超過 x。策略如下:

貪心地模擬分割的過程,從前到後遍歷陣列,用 sum 表示當前分割子陣列的和,cnt 表示已經分割出的子陣列的數量(包括當前子陣列),那麼每當 sum 加上當前值超過了 x,我們就把當前取的值作為新的一段分割子陣列的開頭,並將 cnt 加 1。遍歷結束後驗證是否 cnt 不超過 m。

這樣我們可以用二分查詢來解決。二分的上界為陣列 nums 中所有元素的和,下界為陣列 nums 中所有元素的最大值,通過二分查詢,我們可以得到最小的最大分割子陣列和,這樣就可以得到最終的答案:

class

solution

:def

splitarray

(self, nums: list[

int]

, m:

int)

->

int:

defcheck

(x:int)-

>

bool

: total, cnt =0,

1for num in nums:

if total + num > x:

cnt +=

1 total = num

else

: total += num

return cnt <= m

left =

max(nums)

#下界 right =

sum(nums)

#上界while left < right:

#二分法,在上界和下界之間找乙個值

mid =

(left + right)//2

if check(mid)

: right = mid

else

: left = mid +

1return left

sum/solution/fen-ge-shu-zu-de-zui-da-zhi-by-leetcode-solution/

貪心 LeetCode410 分割陣列的最大值

給定乙個非負整數陣列和乙個整數 m,你需要將這個陣列分成 m 個非空的連續子陣列。設計乙個演算法使得這m 個子陣列各自和的最大值最小。注意 陣列長度 n 滿足以下條件 1 n 1000 1 m min 50,n 輸入 nums 7,2,5,10,8 m 2 輸出 18 解釋 一共有四種方法將nums...

LeetCode410 分割陣列的最大值

leetcode410.分割陣列的最大值 給定乙個非負整數陣列和乙個整數 m,你需要將這個陣列分成 m 個非空的連續子陣列。設計乙個演算法使得這 m 個子陣列各自和的最大值最小。注意 陣列長度 n 滿足以下條件 1 n 1000 1 m min 50,n 示例 輸入 nums 7,2,5,10,8 ...

LeetCode 410 分割陣列的最大值

給定乙個非負整數陣列和乙個整數 m,你需要將這個陣列分成 m 個非空的連續子陣列。設計乙個演算法使得這 m 個子陣列各自和的最大值最小。注意 陣列長度 n 滿足以下條件 1 n 1000 1 m min 50,n 示例 輸入 nums 7,2,5,10,8 m 2 輸出 18 解釋 一共有四種方法將...