📌  相关文章
📜  通过最小化每个元素,N-1 次操作中的最大数组最小值(1)

📅  最后修改于: 2023-12-03 15:28:26.954000             🧑  作者: Mango

通过最小化每个元素,N-1 次操作中的最大数组最小值

简介

给定一个包含 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
参考链接