问题背景
给你一个整数数组 n u m s nums nums,其中 n u m s [ i ] nums[i] nums[i] 表示第 i i i 个袋子里球的数目。同时给你一个整数 m a x O p e r a t i o n s maxOperations maxOperations。
你可以进行如下操作至多 m a x O p e r a t i o n s maxOperations maxOperations 次:
选择任意一个袋子,并将袋子里的球分到 2 2 2 个新的袋子中,每个袋子里都有 正整数 个球。
- 比方说,一个袋子里有 5 5 5 个球,你可以把它们分到两个新袋子里,分别有 1 1 1 个和 4 4 4 个球,或者分别有 2 2 2 个和 3 3 3 个球。
你的开销是单个袋子里球数目的 最大值 ,你想要 最小化 开销。
请你返回进行上述操作后的最小开销。
数据约束
- 1 ≤ n u m s . l e n g t h ≤ 1 0 5 1 \le nums.length \le 10 ^ 5 1≤nums.length≤105
- 1 ≤ m a x O p e r a t i o n s , n u m s [ i ] ≤ 1 0 9 1 \le maxOperations, nums[i] \le 10 ^ 9 1≤maxOperations,nums[i]≤109
解题过程
遇到最小化最大值,最大化最小值,要考虑二分答案法。
这题可能的结果范围就是由数组中的最小最大值构成的,在这个范围上,每组中可放的球越少,要操作的次数就越多。
二分的标准,是按照当前数量分组能不能满足在规定的最大操作次数以内完成分割。
具体实现
java
class Solution {
public int minimumSize(int[] nums, int maxOperations) {
int max = 0;
for (int num : nums) {
max = Math.max(max, num);
}
int left = 1;
int right = max;
while (left < right) {
int mid = left + ((right - left) >>> 1);
if (check(nums, maxOperations, mid)) {
right = mid;
} else {
left = mid + 1;
}
}
return left;
}
private boolean check(int[] nums, int maxOperations, int max) {
long res = 0;
for (int num : nums) {
res += (num - 1) / max;
}
return res <= maxOperations;
}
}