📅  最后修改于: 2023-12-03 15:39:17.167000             🧑  作者: Mango
给定一个正整数数组 nums
和一个正整数 k
,找出一个最小的正整数 m
,使得数组中所有元素相除的和不超过 k
,即:
(nums[0] / m) + (nums[1] / m) + ... + (nums[nums.length-1] / m) <= k
其中 /
表示整除操作,即两个整数相除向下取整。
该问题可以利用二分查找来进行求解。
首先,我们注意到当 m
取值越大时,上述等式的左侧会越小,因为有更多的除数。因此,我们可以利用二分查找来逐步缩小 m
的取值范围。
具体来说,我们可以设定一个区间 $[l,r]$,其中 l
和 r
分别表示 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
中的最大值。