Given an array nums
which consists of non-negative integers and an integer m
, you can split the array into m
non-empty continuous subarrays.
Write an algorithm to minimize the largest sum among these m
subarrays.
Example 1:
Input: nums = [7,2,5,10,8], m = 2
Output: 18
Explanation:
There are four ways to split nums into two subarrays.
The best way is to split it into [7,2,5] and [10,8],
where the largest sum among the two subarrays is only 18.
Example 2:
Input: nums = [1,2,3,4,5], m = 2
Output: 9
Example 3:
Input: nums = [1,4,4], m = 3
Output: 4
Constraints:
1 <= nums.length <= 1000
0 <= nums[i] <= 10<sup>6</sup>
1 <= m <= min(50, nums.length)
这是动态规划中很经典的划分问题,和1335题的任务调度问题很相似,都是给一个集合,让你划分成XXX,然后给你一个规则来找出这个规则下的最优解。
func splitArray(nums []int, m int) int {
n := len(nums)
dp := make([][]int, n + 1)
sub := make([]int, n + 1)
for i := 0; i < len(dp); i++ {
dp[i] = make([]int, m + 1)
for j := 0; j < len(dp[i]); j++ {
dp[i][j] = 1 << 31 - 1
}
}
// 前缀和加速
for i := 0; i < n; i++ {
sub[i + 1] = sub[i] + nums[i]
}
dp[0][0] = 0
for i := 1; i <= n; i++ {
// 从分成1份开始,一直到分成m份
for j := 1; j <= m; j++ {
// 然后看前k个数,分成j-1份,
// 就是前半部分的解(备忘录已经算好),和最后一部分的和值(前缀和)比较,来做状态转移
for k := 0; k < i; k++ {
// sub[i] - sub[k] 使用前缀和,快速求出最后一段的和值
dp[i][j] = min(dp[i][j], max(dp[k][j - 1], sub[i] - sub[k]))
}
}
}
return dp[n][m]
}
func min(i, j int) int {
if i < j {
return i
}
return j
}
func max(i, j int) int {
if i > j {
return i
}
return j
}