2226-每个小孩最多能分到多少糖果
给你一个 下标从 0 开始 的整数数组 candies
。数组中的每个元素表示大小为 candies[i]
的一堆糖果。你可以将每堆糖果分成任意数量的 子堆 ,但 无法 再将两堆合并到一起。
另给你一个整数 k
。你需要将这些糖果分配给 k
个小孩,使每个小孩分到 相同 数量的糖果。每个小孩可以拿走 至多一堆
糖果,有些糖果可能会不被分配。
返回每个小孩可以拿走的 最大糖果数目 __ 。
示例 1:
**输入:** candies = [5,8,6], k = 3
**输出:** 5
**解释:** 可以将 candies[1] 分成大小分别为 5 和 3 的两堆,然后把 candies[2] 分成大小分别为 5 和 1 的两堆。现在就有五堆大小分别为 5、5、3、5 和 1 的糖果。可以把 3 堆大小为 5 的糖果分给 3 个小孩。可以证明无法让每个小孩得到超过 5 颗糖果。
示例 2:
**输入:** candies = [2,5], k = 11
**输出:** 0
**解释:** 总共有 11 个小孩,但只有 7 颗糖果,但如果要分配糖果的话,必须保证每个小孩至少能得到 1 颗糖果。因此,最后每个小孩都没有得到糖果,答案是 0 。
提示:
1 <= candies.length <= 105
1 <= candies[i] <= 107
1 <= k <= 1012
方法一:二分查找转化为判定问题
提示 1
当每个小孩拿走的糖果数目增大时,现有糖果可以满足的小孩数目不会增大。
思路与算法
根据 提示 1,如果 k 个小孩每人可以按要求拿到 i 个糖果,那么它们一定可以按要求拿到闭区间 [0, i] 内任一整数数量的糖果。这也就说明「k 个小孩每人能否按要求拿到 i 个糖果」这一判定问题对于 i 具有二值性。因此我们可以通过二分查找确定使得该判定问题成立的最大的 i。
我们可以引入辅助函数 check}(i) 来判断对应的判定问题是否成立。具体地,我们用 res 来维护最多可以按要求拿到 i 个糖果的小孩数目。我们遍历 candies 数组,对于数组的每个元素 c,对应数量该堆糖果最多可以分给 \lfloor c / i \rfloor 个小孩(其中 \lfloor \dots \rfloor 代表向下取整),则我们将 res 加上该数值。最终,我们通过判断 res 是否大于等于 k 来判断对应的判定问题是否成立。
而对于二分查找的上界,我们可以通过糖果数量进行估计。具体地,由于每个小孩至多可以拿走一堆糖果,因此每个小孩可以拿走的糖果数目不会超过最多一堆糖果的数量。
细节
对于二分查找的下界,如果设置为 0,则在上文的未经修改的 check}(i) 函数中,会出现除数为零的问题。此时我们有两种解决方案:
将二分查找下界设置为 1,通过二分查找计算最小的无法满足需求的 i,此时每个小孩可分到的最大糖果数目即为 i - 1;
由于 i = 0 时一定可以满足 k 个小孩的要求,因此我们直接对于此种情况返回 true 即可。
代码
1 | class Solution { |
1 | class Solution: |
复杂度分析
时间复杂度:O(n \log M),其中 n 为数组 candies 的长度,M = \max(\textit{candies}),即二分查找的上界。我们总共需要 O(\log M) 次二分查找,每次需要 O(n) 的时间计算每人的糖果数量是否符合要求。
空间复杂度:O(1)。