📌  相关文章
📜  将所有数组元素相除以生成总和不超过 K 的商的最小正整数(1)

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

将所有数组元素相除以生成总和不超过 K 的商的最小正整数
问题描述

给定一个正整数数组 nums 和一个正整数 k,找出一个最小的正整数 m,使得数组中所有元素相除的和不超过 k,即:

(nums[0] / m) + (nums[1] / m) + ... + (nums[nums.length-1] / m) <= k

其中 / 表示整除操作,即两个整数相除向下取整。

解决方案

该问题可以利用二分查找来进行求解。

首先,我们注意到当 m 取值越大时,上述等式的左侧会越小,因为有更多的除数。因此,我们可以利用二分查找来逐步缩小 m 的取值范围。

具体来说,我们可以设定一个区间 $[l,r]$,其中 lr 分别表示 m 的可能最小值和最大值。对于每个中间值 mid = (l+r) / 2,我们计算 nums 中所有元素除以 mid 后的和 s,判断 s 是否小于等于 k。如果小于等于 k,则说明 mid 可以取得更小,我们将 r 更新为 mid,否则说明 mid 太小了,我们将 l 更新为 mid+1。当区间最终收缩为 l=r 时,l 即为所求的最小正整数。

代码实现

以下是该问题的代码实现。其中,使用 lowbit 函数来计算每个 mid 对应的 sum,可以将时间复杂度降为 $O(n \log_2 m)$。

class Solution:
    def smallestDivisor(self, nums: List[int], threshold: int) -> int:
        def lowbit(x: int) -> int:
            return x & -x

        l, r = 1, max(nums)
        while l < r:
            mid = (l+r) // 2
            s = sum((num-1)//mid+1 for num in nums)
            if s <= threshold:
                r = mid
            else:
                l = mid+1
        return l

该代码的时间复杂度为 $O(n \log_2 m)$,其中 $n$ 表示数组 nums 的长度,$m$ 表示数组 nums 中的最大值。