📅  最后修改于: 2023-12-03 15:09:36.975000             🧑  作者: Mango
给定一个正整数数组 nums 和一个正整数 k,将数组划分为 k 个非空连续子数组,使得每个子数组的平均数之和最小。请输出这个最小的平均数。
这道题可以使用二分查找来解决。
首先我们需要求出最小的平均数区间,显然这个平均数的取值范围是 [max(nums), sum(nums)]
。我们可以使用二分查找来缩小这个范围,找到最小的满足条件的平均数值。
我们可以从左到右依次扫描数组,对于每个数,我们累加它的值,并将其加到当前的子数组中。当当前子数组的平均值大于了目标平均值时,我们就把当前子数组分割出来。
如果最后分割出来的子数组个数大于 k,说明平均数太小了,需要增大平均数的值;反之,说明平均数太大了,需要减小平均数的值。
def can_partition(nums: List[int], k: int) -> bool:
# 可以分割的子数组的最大值的范围是 [max(nums), sum(nums)]
left, right = max(nums), sum(nums)
while left <= right:
mid = (left + right) // 2
if valid(nums, k, mid):
right = mid - 1
else:
left = mid + 1
return left - 1
def valid(nums: List[int], k: int, target: int) -> bool:
# 将数组划分为 k 个非空连续子数组,使得每个子数组的平均数之和最小。
# 满足条件的 k 个子数组的最小值不小于 target
cnt, total = 1, 0
for num in nums:
total += num
if total > target:
cnt += 1
total = num
if cnt > k:
return False
return True
该算法使用二分查找来缩小平均数的范围,每次二分需要遍历一遍整个数组来统计子数组的个数,每次遍历的时间复杂度为 O(n),最多进行 log(sum(nums)-max(nums)) 次二分,因此总时间复杂度为 O(n * log(sum(nums)-max(nums)))。
参考链接: