410分割数组的最大值
题目:给定一个非负整数数组和一个整数 m,你需要将这个数组分成 m 个非空的连续子数组。设计一个算法使得这 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]
法二:二分法
思路:二分法的关键是对什么进行分割搜索,这道题显然不能对索引进行分割搜索,而是直接对最后的结果进行二分搜索,最后的结果要求的是最大和值中的最小值,于是可以对最后的这个最小值进行二分,每确定一个最小值,相应的就可以确定一个分割的组数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)
ttt