在问 · 算法题解

410. 分割数组的最大值

困难动态规划二分答案 + 贪心力扣原题 ↗

题目描述

输入一个非负整数数组 nums 和一个整数 k。把 nums 切成恰好 k 段,每段都是非空的连续子数组,所有段合起来正好是原数组。

对每种切法,计算各段元素和中的最大值。返回所有切法里这个最大值能取到的最小值。

示例 1
输入:nums = [7,2,5,10,8], k = 2
输出:18

解释:切成 [7,2,5] 和 [10,8],两段和为 14 和 18,最大值 18 是所有切法中最小的。

示例 2
输入:nums = [1,2,3,4,5], k = 2
输出:9

解释:切成 [1,2,3] 和 [4,5],两段和为 6 和 9。

数据范围

  • 1 <= nums.length <= 1000
  • 0 <= nums[i] <= 10^6
  • 1 <= k <= min(50, nums.length)

解题思路:二分答案 + 贪心

反过来问:“每段和不超过 mid 时,最少要分几段?”贪心地从左往右装,装不下就开新段,得到最少段数 cnt。mid 越大 cnt 越小,具有单调性,所以在 [max(nums), sum(nums)] 上二分:cnt <= k 说明 mid 可行(段数少了可以再拆开),往小找;否则往大找。

为什么正确

答案始终在 [lo, hi] 内:hi 总是可行的上限,lo 左边的值都已确认不可行。

复杂度分析

时间 O(n log S),S 为数组和。额外空间 O(1)。

易错点

下界要取 max(nums) 而不是 0,否则单个大元素装不进任何段,贪心计数会出错。判断条件是 cnt <= k,不是 cnt == k。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def splitArray(self, nums: List[int], k: int) -> int:
        lo, hi = max(nums), sum(nums)
        while lo < hi:
            mid = (lo + hi) // 2
            cnt, cur = 1, 0
            for x in nums:
                if cur + x > mid:
                    cnt += 1
                    cur = 0
                cur += x
            if cnt <= k:
                hi = mid
            else:
                lo = mid + 1
        return lo

载入编辑器,自己跑一遍 →

其他解法

动态规划枚举每种切分位置求最优值;二分答案利用“最大段和越大越容易满足”的单调性,配合贪心检查,复杂度低得多。

解法 2:动态规划 时间 O(n²k),空间 O(nk)

设 S 为数组元素之和。f[i][j] 表示把前 i 个数分成 j 段时,各段和最大值的最小可能值。枚举最后一段的起点 p,f[i][j] = min(max(f[p][j - 1], sum(p..i-1))),区间和用前缀和 O(1) 求出。初始 f[0][0] = 0,其余为无穷大,答案是 f[n][k]。

直接按定义划分状态,思路自然,不依赖答案的单调性。复杂度 O(n²k),n = 1000、k = 50 时约 5×10⁷ 次运算,明显慢于二分答案。

class Solution:
    def splitArray(self, nums, k):
        n = len(nums)
        pre = [0] * (n + 1)
        for i, x in enumerate(nums):
            pre[i + 1] = pre[i] + x
        INF = float('inf')
        f = [[INF] * (k + 1) for _ in range(n + 1)]
        f[0][0] = 0
        for i in range(1, n + 1):
            for j in range(1, min(i, k) + 1):
                best = INF
                for p in range(j - 1, i):
                    cur = max(f[p][j - 1], pre[i] - pre[p])
                    if cur < best:
                        best = cur
                f[i][j] = best
        return f[n][k]

动态规划 专题的其他题目

查看 动态规划 全部题目 →