LeetCode 题解工作台

分割数组的最大值

给定一个非负整数数组 nums 和一个整数 k ,你需要将这个数组分成 k 个非空的连续子数组,使得这 k 个子数组各自和的最大值 最小 。 返回分割后最小的和的最大值。 子数组 是数组中连续的部分。 示例 1: 输入: nums = [7,2,5,10,8], k = 2 输出: 18 解释: 一…

category

5

题型

code_blocks

6

代码语言

hub

3

相关题

当前训练重点

困难 · 状态·转移·动态规划

bolt

答案摘要

我们注意到,当子数组的和的最大值越大,子数组的个数越少,当存在一个满足条件的子数组和的最大值时,那么比这个最大值更大的子数组和的最大值一定也满足条件。也就是说,我们可以对子数组和的最大值进行二分查找,找到满足条件的最小值。 我们定义二分查找的左边界 $left = \max(nums)$,右边界 $right = sum(nums)$,然后对于二分查找的每一步,我们取中间值 $mid = \lfl…

Interview AiBox logo

Interview AiBox 实时 AI 助手,陪你讲清 状态·转移·动态规划 题型思路

试试 AiBox 面试助手arrow_forward
description

题目描述

给定一个非负整数数组 nums 和一个整数 k ,你需要将这个数组分成 k 个非空的连续子数组,使得这 k 个子数组各自和的最大值 最小

返回分割后最小的和的最大值。

子数组 是数组中连续的部分。

 

示例 1:

输入:nums = [7,2,5,10,8], k = 2
输出:18
解释:
一共有四种方法将 nums 分割为 2 个子数组。 
其中最好的方式是将其分为 [7,2,5] 和 [10,8] 。
因为此时这两个子数组各自的和的最大值为18,在所有情况中最小。

示例 2:

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

示例 3:

输入:nums = [1,4,4], k = 3
输出:4

 

提示:

  • 1 <= nums.length <= 1000
  • 0 <= nums[i] <= 106
  • 1 <= k <= min(50, nums.length)
lightbulb

解题思路

方法一:二分查找

我们注意到,当子数组的和的最大值越大,子数组的个数越少,当存在一个满足条件的子数组和的最大值时,那么比这个最大值更大的子数组和的最大值一定也满足条件。也就是说,我们可以对子数组和的最大值进行二分查找,找到满足条件的最小值。

我们定义二分查找的左边界 left=max(nums)left = \max(nums),右边界 right=sum(nums)right = sum(nums),然后对于二分查找的每一步,我们取中间值 mid=left+right2mid = \lfloor \frac{left + right}{2} \rfloor,然后判断是否存在一个分割方式,使得子数组的和的最大值不超过 midmid,如果存在,则说明 midmid 可能是满足条件的最小值,因此我们将右边界调整为 midmid,否则我们将左边界调整为 mid+1mid + 1

我们如何判断是否存在一个分割方式,使得子数组的和的最大值不超过 midmid 呢?我们可以使用贪心的方法,从左到右遍历数组,将数组中的元素依次加入到子数组中,如果当前子数组的和大于 midmid,则我们将当前元素加入到下一个子数组中。如果我们能够将数组分割成不超过 kk 个子数组,且每个子数组的和的最大值不超过 midmid,则说明 midmid 是满足条件的最小值,否则 midmid 不是满足条件的最小值。

时间复杂度 O(n×logm)O(n \times \log m),空间复杂度 O(1)O(1)。其中 nnmm 分别是数组的长度和数组所有元素的和。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution:
    def splitArray(self, nums: List[int], k: int) -> int:
        def check(mx):
            s, cnt = inf, 0
            for x in nums:
                s += x
                if s > mx:
                    s = x
                    cnt += 1
            return cnt <= k

        left, right = max(nums), sum(nums)
        return left + bisect_left(range(left, right + 1), True, key=check)
speed

复杂度分析

指标
时间Depends on the final approach
空间Depends on the final approach
psychology

面试官常问的追问

外企场景
  • question_mark

    Understanding how binary search can be applied in optimization problems is crucial.

  • question_mark

    Recognizing when to switch between greedy algorithms and dynamic programming is key for this problem.

  • question_mark

    The candidate should be able to efficiently identify the correct partitioning strategy based on dynamic constraints.

warning

常见陷阱

外企场景
  • error

    Misunderstanding the binary search boundaries. Ensure that the lower boundary starts from the maximum element in the array.

  • error

    Incorrect greedy approach leading to too many subarrays. It's important to balance the subarray sums correctly.

  • error

    Failure to optimize dynamic programming transitions efficiently, leading to unnecessary computations and increased complexity.

swap_horiz

进阶变体

外企场景
  • arrow_right_alt

    Allowing k to be a dynamic value, where it changes based on additional constraints or conditions.

  • arrow_right_alt

    Adapting the problem to handle negative numbers in nums, which may change how partitions are handled.

  • arrow_right_alt

    Optimizing the solution further using a more efficient greedy strategy or advanced dynamic programming techniques.

help

常见问题

外企场景

分割数组的最大值题解:状态·转移·动态规划 | LeetCode #410 困难