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 解釋 一共有四種方法將...