📅  最后修改于: 2023-12-03 15:28:26.954000             🧑  作者: Mango
给定一个包含 N 个整数的数组 nums,你可以通过将 nums 中的任意元素乘以 -1 的方式 N-1 次操作来使该数组具有均值最小的性质。例如,如果 nums = [1, -2, 3],则可以将 -2 变为 2 来获得新的数组 [1, 2, 3],其均值为 2 和原始数组的均值相同。请选择数组 nums 中的一个元素 x,并将每个元素乘以 -1,但不包括 x 本身。
问在进行 N-1 次操作后,最大的数组均值最小值是多少?答案与 10^-5 的绝对误差内保持一致。
首先,我们可以注意到,如果将每个元素乘以 -1,那么对于每个元素 i,原数组中的和 sum 会减去 2*nums[i],因为 nums[i] 会被乘以 -1,sum 的值就会减去 2*nums[i]。
那么第 i 个元素被改变之后新数组的和就是 sum-2*nums[i],那么新数组的平均值就是 (sum-2*nums[i])/(N-1)。
我们需要让新数组的平均值最小,因此我们需要使得 (sum-2*nums[i])/(N-1) 尽可能的小,这等价于让 sum-2*nums[i] 尽可能的小,即让 nums[i] 最大。因此,我们需要求出在 N-1 次操作中,每个元素最大的值。
对于最大的元素值 x,我们将它乘以 -1 后,剩下的元素进行一次求和操作,即可得到 (sum+x)/(N-1) 所得到的最小值,也就是最大数组均值最小值。
我们可以使用二分查找来寻找最大的元素值。假设最大元素值的上下界为 left 和 right,那么我们每次可以取它们的中间值 mid,然后判断 mid 是否满足要求。如果 mid 不满足要求,那么最大元素值一定在 [mid+1, right] 中,否则最大元素值一定在 [left, mid-1] 中。在找到最大元素值之后,我们只需要计算一次求和操作即可得到最大数组均值最小值。
时间复杂度为 O(NlogM),其中 N 是数组 nums 的长度,M 是 nums 中元素的最大值减最小值。
from typing import List
class Solution:
def findMaxAverage(self, nums: List[int], k: int) -> float:
left, right = min(nums), max(nums)
while right - left >= 1e-5:
mid = (left + right) / 2
if self.check(nums, mid, k):
right = mid
else:
left = mid
return left
def check(self, nums: List[int], max_val: float, k: int) -> bool:
sum_val = 0
for i in range(k):
sum_val += nums[i] - max_val
if sum_val >= 0:
return True
pre_sum_val = 0
min_sum_val = 0
for i in range(k, len(nums)):
sum_val += nums[i] - max_val
pre_sum_val += nums[i-k] - max_val
min_sum_val = min(min_sum_val, pre_sum_val)
if sum_val - min_sum_val >= 0:
return True
return False