LeetCode-Python-410. 分割数组的最大值

给定一个非负整数数组和一个整数 m,你需要将这个数组分成 个非空的连续子数组。设计一个算法使得这 个子数组各自和的最大值最小。

注意:
数组长度 满足以下条件:

  • 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,在所有情况中最小。

思路:

首先分析题意,可以得出结论,结果必定落在【max(nums), sum(nums)】这个区间内,因为左端点对应每个单独的元素构成一个子数组,右端点对应所有元素构成一个子数组。

然后可以利用二分查找法逐步缩小区间范围,当区间长度为1时,即找到了最终答案。

每次二分查找就是先算一个mid值,这个mid就是代表当前猜测的答案,然后模拟一下划分子数组的过程,可以得到用这个mid值会一共得到的子区间数cnt,然后比较cnt和m的关系,来更新区间范围。

本题跟1014. 在 D 天内送达包裹的能力非常类似。

class Solution(object):
    def splitArray(self, nums, m):
        """
        :type nums: List[int]
        :type m: int
        :rtype: int
        """
        # max(nums), sum(nums)
        if len(nums) == m:
            return max(nums)
        lo, hi = max(nums), sum(nums)
        while(lo < hi):
            mid = (lo + hi) // 2 # 最大和
            
            #------以下在模拟划分子数组的过程
            temp, cnt = 0, 1
            for num in nums:
                temp += num
                # cnt += 1
                if temp > mid:#说明当前这个子数组的和已经超过了允许的最大值mid,需要把当前元素放在下一个子数组里
                    temp = num
                    cnt += 1
            # print temp, cnt, mid
            #------以上在模拟划分子数组的过程
            
            if cnt > m: #说明分出了比要求多的子数组,多切了几刀,说明mid应该加大,这样能使子数组的个数减少
                lo = mid + 1
            elif cnt <= m:
                hi = mid

                
        return lo
            

以下是这种题型的可能的包装方法:

摘自:https://www.1point3acres.com/bbs/forum.php?mod=viewthread&tid=499490&extra=&page=1

这题的剧本应该就是先问清题意,再简要说一下DP能怎么做,再来就直接开二分法,尝试把巧克力分成K分每一分都要超过一个猜测的Target,利口肆妖灵的反题

分享一下这题和反过来的利口肆衣领见过的几种包装方法:
1. 一片巧克力数组分成K块,数字代表甜度,第一个人会想拿最甜的一块,把他平分成一个状态使得第一个人拿到的总甜度是最小的,求第一人拿到的甜度
2. 一个必须依照数组顺序完成的工作,数字代表工作难易度,分成K天完工,尽可能把困难度最高的一天变得比较不累,求最累的一天的困难度
3. 一个数组代表一排的书,数字代表页数,现在必须把相邻的书分成K组放置到K台打印机,设置一个配置方法使得需要打印最多页数的机器打印最少页,求工作量最多的打印机需要打印的页数
4. 一个包裹数组,数字代表重量,依包裹排列顺序分成K批寄送,使得最重的一批重量最小,求最重一批重量(利口比赛刚出的)

你可能感兴趣的:(Leetcode,Python)