410分割数组的最大值

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

链接:https://leetcode-cn.com/problems/split-array-largest-sum/

法一:自己的代码     超时,不能用

思路:典型的二维动态规划

from typing import List
class Solution:
    def splitArray(self, nums: List[int], m: int) -> int:
        size = len(nums)
        dp = [[0] * m for i in range(size)]
        # 先对第一列特殊处理
        dp[0][0] = nums[0]
        for i in range(1,size):
            dp[i][0] = dp[i-1][0] + nums[i]
        # dp[i][j]表示nums前i个数分成j组的和的最大值中的最小值
        for col in range(1, m):
            for row in range(col,size):
                dp[row][col] = min(max(dp[i][col-1], sum(nums[i+1:row+1])) for i in range(row))
        return dp[-1][-1]
View Code

法二:二分法

思路:二分法的关键是对什么进行分割搜索,这道题显然不能对索引进行分割搜索,而是直接对最后的结果进行二分搜索,最后的结果要求的是最大和值中的最小值,于是可以对最后的这个最小值进行二分,每确定一个最小值,相应的就可以确定一个分割的组数k,而组数必须是m,所以为了使k=m,就要缩小搜索区间,最终使k=m,

from typing import List
class Solution:
    def splitArray(self, nums: List[int], m: int) -> int:
        left, right = max(nums),sum(nums)
        while left < right:
            mid = (left + right) // 2
            # cnt表示子数组的最大和大于mid的情况下,分组的的最小值,
            sums, cnt = 0, 1
            for i in nums:
                # 这里是关键,如果此时的分组的和将要超过最大值了,则开始下一个分组
                # 这样就保证了每个分组的和都不超过最大值,
                if sums + i > mid:
                    cnt += 1
                    sums = i
                else:
                    sums += i
            # 小于m,说明分组太少,导致最大值太大,故缩小最大值的右边界
            if cnt <= m:
                right = mid
            # 大于m,说明分组太多,导致最大值太小,故增大最大值的左边界
            else:
                left = mid + 1
        return left
if __name__ == '__main__':
    solution = Solution()
    # result = solution.splitArray(nums=[1,2,3,1,1,1,1,1,1], m=3)
    result = solution.splitArray(nums=[1,2,3,1,1,1,1,1,1], m=3)
    print(result)
View Code

ttt

原文地址:https://www.cnblogs.com/xxswkl/p/12380927.html