LeetCode刷题笔记2---分割数组的最大值

**题干:**

给定一个非负整数数组和一个整数 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,在所有情况中最小。

**题解:**

(下面所有变量均与程序中一致,用python编写)
该题可以使用两种思路进行解答:①动态规划问题②二分法
由于暂时只琢磨透了二分法的思想,故以下先将二分法的思想做个介绍。
②二分法
二分法找到使得各个分段和的最大值最小,显然,这个值天然存在上下限,上限为数组所有值的和sum(nums),下限则为数组中的最小值min(nums)。
令cnt为当前分段数量,且cnt<=m(最终要分成m段,所以当前分段小于等于m)。
最关键的思想是二分逼近,我们要找寻一个较大的值,让每个分段的和小于这个值,而这个值就是二分点的值,即我们令左端的值为left,右端为right,该值为mid,mid = (left + right) // 2。
如果cnt <= m, 说明分段的数目少了,则分段中和最大的值就比预计的值偏大,此时就让right指针左移,right = mid。
如果 cnt > m, 说明分段的数目多了,则分段中和最大的值就会比预计的值偏小,此时就让left指针右移,left = mid + 1。
在这里插入图片描述
这里就存在一个问题,如何获取当前分段数量cnt。

这里可以通过跟踪求和的方法:
1.先初始化分段和total,mid。
2.从头到尾遍历数组,让当前分段和与mid比较
3.若当前分段和total+num > mid, cnt自增1,并令当前位置数值为下一分段起始位置继续循环
4.反之,total += num
5.循环完毕则可以得出cnt,返回

**代码**
class Solution:
    def splitArray(self, nums: List[int], m: int) -> int:
        def check(mid):
            total, cnt = 0, 1
            for num in nums:
                if total + num > mid:
                    cnt += 1
                    total = num
                else:
                    total += num
            return cnt<m

        left = max(nums)
        right = sum(nums)
        while left < right:
            mid = (left + right) // 2
            # 判断cnt是否小于m
            if check(mid):
                right = mid
            else:
                left = mid + 1
        return left

你可能感兴趣的:(python刷题,二分法,leetcode,算法)