📜  门| GATE MOCK 2017 |问题15(1)

📅  最后修改于: 2023-12-03 15:42:14.756000             🧑  作者: Mango

门| GATE MOCK 2017 |问题15

题目描述

有一个序列,由n个整数组成,现在需要将这个序列划分成m个不相交的连续段,每个段中元素的和的最大值是最小的。例如,序列[1, 2, 3, 4, 5]可以划分成[1, 2], [3], [4], [5],最大和是5。

给定一个长度为n的序列和整数m,求解最大和的最小值。

思路

这道题可以使用二分搜索+贪心。

我们二分答案mid,然后贪心的去划分序列,保证划分出的m个连续段中每一个段的和都不超过mid,我们记这个贪心的实现为check()函数。

当某一个mid可以使得check(mid)为true的时候,我们将搜索的范围缩小到(mid, end],因为我们要求最小的最大值,我们要尽量往小了缩小范围,而不是去增加。

当某一个mid使得check(mid)为false,那么代表着当每一个连续段中元素和的最大值不能超过mid时,n个数无法被划分成m个不相交的连续段,那么我们就将搜索的范围缩小到[start, mid]。

最后当搜索的范围缩小到只有一个数的时候,这个数就是最终的答案。

代码实现
from typing import List

def check(nums: List[int], mid: int, m: int) -> bool:
    cnt = 0
    sum_ = 0
    for num in nums:
        sum_ += num
        if sum_ > mid:
            cnt += 1
            sum_ = num
    cnt += 1
    return cnt <= m

def split_array(nums: List[int], m: int) -> int:
    start = max(nums)
    end = sum(nums)
    while start < end:
        mid = (start + end) // 2
        if check(nums, mid, m):
            end = mid
        else:
            start = mid + 1
    return start

返回的结果应当是int类型,数值为最大和的最小值。

复杂度分析

算法的时间复杂度为O(nlogn),因为二分搜索和check函数都是有n次操作的。算法的空间复杂度为O(1),因为我们并没有使用任何额外的空间。

总结

这道题是一道比较经典的二分搜索题目,同时也巧妙地使用了贪心算法,对于熟悉二分搜索和贪心算法的程序猿而言,会比较容易理解和完成。