开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第31天,点击查看活动详情
1760. 袋子里最少数目的球
给你一个整数数组 nums ,其中 nums[i] 表示第 i 个袋子里球的数目。同时给你一个整数 maxOperations 。
你可以进行如下操作至多 maxOperations 次:
-
选择任意一个袋子,并将袋子里的球分到 2 个新的袋子中,每个袋子里都有 正整数 个球。
- 比方说,一个袋子里有
5个球,你可以把它们分到两个新袋子里,分别有1个和4个球,或者分别有2个和3个球。
- 比方说,一个袋子里有
你的开销是单个袋子里球数目的 最大值 ,你想要 最小化 开销。
请你返回进行上述操作后的最小开销。
示例 1:
输入: nums = [9], maxOperations = 2
输出: 3
解释:
- 将装有 9 个球的袋子分成装有 6 个和 3 个球的袋子。[9] -> [6,3] 。
- 将装有 6 个球的袋子分成装有 3 个和 3 个球的袋子。[6,3] -> [3,3,3] 。
装有最多球的袋子里装有 3 个球,所以开销为 3 并返回 3 。
提示:
1 <= nums.length <= 1051 <= maxOperations, nums[i] <= 109
思路
这道题如果没有接触过类似题目的话是很难想到的,这类题目可以通过二分查找来求解。题目可以转换为:给定操作数 oper,能否使每个袋子中球的数量不超过 n。
对于袋子中的球数,我们可以通过二分查找来确定,如果每个袋子要达到 n 个球,我们去计算每个袋子所需的操作数,若总操作数大于了要求的最大操作数,则说明此时袋子中最大球数太小,应该增大最大球数。 若总操作数小于等于最大操作数,说明此时的最大球数还可以缩小,我们可以缩小最大球数,以求得最小的最大球数。
对于每个袋子来说,我们需要求得使其减少至最大操作数,如果当前球数等于最大操作数,则不需要调整,操作数为零,大于最大操作数,则操作数为球数/最大操作数,即(num - 1) / max。
题解
class Solution {
public int minimumSize(int[] nums, int maxOperations) {
int left = 1, right = Arrays.stream(nums).max().getAsInt();
while(left <= right) {
int mid = left + ((right - left) >> 1);
long oper = 0;
for(int num: nums) {
oper += (num - 1) / mid;
}
if(oper <= maxOperations) {
right = mid - 1;
}else {
left = mid + 1;
}
}
return left;
}
}