📌  相关文章
📜  生成可以在 P 步中删除的最小和的数组(1)

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

生成可以在 P 步中删除的最小和的数组

有一个长度为 n 的正整数数组 nums,请你构造一个长度为 n 的数组 ans,每个 ans[i] 都等于 nums[i] 与数组中所有其他元素之和的差,其中 ans 数组下标从 0 开始计数。

换句话说,ans[i] 等于 nums[i] 和原数组中所有其他元素之和的差的绝对值之和。

你需要删除最多 P 个元素以使 ans 数组中所有元素之和最小。

请你返回满足要求的 ans 数组中所有元素之和的最小值。

示例

输入:nums = [1,2,3,4,5], P = 2

输出:13

解释:从数组中删除数字 2 和 3 ,得到 nums = [1,4,5] 。构造得到 ans 数组为 [3,0,-3] ,所有元素之和为 6 + 0 + (-3) = 3 。

思路

本题需要构造出 ans 数组,使其满足题目条件。首先,我们需要知道 ans 数组元素的计算公式:

ans[i] = abs(nums[i] * n - nums的所有元素之和) / (n - 1)

其中 n 为 nums 数组的长度。

根据以上公式,我们可以得到 ans 数组的计算方式。接下来的问题在于如何删除最多 P 个元素使 ans 数组元素之和最小。

我们可以使用二分答案的方式来解决这个问题。首先,我们需要确定 ans 数组元素之和的上下界,因为 ans 数组元素之和一定大于等于 0,所以下界可以设为 0。上界需要计算得到,即将 nums 数组按照从小到大排序,然后选取后面 P 个数,将其从 nums 数组中删除,计算得到 ans 数组的元素之和即可。

得到上下界之后,就可以使用二分答案的方式来计算 ans 数组元素之和了。每次使用 ans 数组元素之和的中间值来计算 ans 数组,然后统计 ans 数组元素之和,如果大于目标值,则缩小上界,如果小于目标值,则缩小下界,直到上下界相等或相邻。

代码

下面是 Python 3 语言的实现代码:

from typing import List

class Solution:
    def minimumAbsDifference(self, nums: List[int], P: int) -> int:
        n = len(nums)
        nums.sort()
        # 计算 ans 数组元素之和的上界
        upper = sum(nums[-P:])
        # 定义二分答案的上下界
        left, right = 0, upper
        # 二分答案
        while left < right:
            mid = (left + right) // 2
            # 构造 ans 数组
            ans = [0] * n
            for i in range(n):
                ans[i] = abs(nums[i] * n - mid) // (n - 1)
            # 删除最多 P 个元素使 ans 数组元素之和最小
            cnt = 0
            for i in range(n):
                cnt += ans[i]
                if cnt > P:
                    break
            if cnt > P:
                left = mid + 1
            else:
                right = mid
        # 返回 ans 数组元素之和
        return left
复杂度分析

本题使用了排序和二分答案两个算法。

排序的时间复杂度为 O(nlogn)。

二分答案的时间复杂度为 O(logC),其中 C 是 ans 数组元素之和的范围,根据题目中的描述,C 最大为 sum(nums)。

总的时间复杂度为 O(nlogn + logC)。

空间复杂度为 O(n),存储 ans 数组。