给你一个整数数组 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 。
示例 2:
输入:nums = [2,4,8,2], maxOperations = 4 输出:2 解释: - 将装有 8 个球的袋子分成装有 4 个和 4 个球的袋子。[2,4,8,2] -> [2,4,4,4,2] 。 - 将装有 4 个球的袋子分成装有 2 个和 2 个球的袋子。[2,4,4,4,2] -> [2,2,2,4,4,2] 。 - 将装有 4 个球的袋子分成装有 2 个和 2 个球的袋子。[2,2,2,4,4,2] -> [2,2,2,2,2,4,2] 。 - 将装有 4 个球的袋子分成装有 2 个和 2 个球的袋子。[2,2,2,2,2,4,2] -> [2,2,2,2,2,2,2,2] 。 装有最多球的袋子里装有 2 个球,所以开销为 2 并返回 2 。
示例 3:
输入:nums = [7,17], maxOperations = 2 输出:7
提示 1
Let's change the question if we know the maximum size of a bag what is the minimum number of bags you can make
提示 2
note that as the maximum size increases the minimum number of bags decreases so we can binary search the maximum size
解法:二分答案
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) {
// 循环不变量:
// check(right + 1),count <= m, 分割数量过少,分割值偏大,应该缩小右边界
// check(left - 1),count > m, 分割数量过多,分割值偏小,应该扩大左边界
int mid = left + (right - left) / 2;
if (check(nums, mid, maxOperations)) {
right = mid - 1;
} else {
left = mid + 1;
}
}
// left == right + 1;
return left;
// 左闭右开区间写法
// int left = 1;
// int right = max + 1;
// while (left < right) {
// // 循环不变量:
// // check(right),count <= m, 分割数量过少,分割值偏大,应该缩小右边界
// // check(left - 1),count > m, 分割数量过多,分割值偏小,应该扩大左边界
// int mid = left + (right - left) / 2;
// if (check(nums, mid, maxOperations)) {
// right = mid;
// } else {
// left = mid + 1;
// }
// }
// // left == right;
// return right;
// 左开右闭区间写法
// int left = 0;
// int right = max;
// while (left < right) {
// // 循环不变量:
// // check(right + 1),count <= m, 分割数量过少,分割值偏大,应该缩小右边界
// // check(left),count > m, 分割数量过多,分割值偏小,应该扩大左边界
// int mid = left + (right - left + 1) / 2;
// if (check(nums, mid, maxOperations)) {
// right = mid - 1;
// } else {
// left = mid;
// }
// }
// // left == right;
// return right + 1;
// 开区间写法
// int left = 0;
// int right = max + 1;
// while (left + 1 < right) {
// // 循环不变量:
// // check(right),count <= m, 分割数量过少,分割值偏大,应该缩小右边界
// // check(left),count > m, 分割数量过多,分割值偏小,应该扩大左边界
// int mid = left + (right - left) / 2;
// if (check(nums, mid, maxOperations)) {
// right = mid;
// } else {
// left = mid;
// }
// }
// // left + 1 == right;
// return right;
}
private boolean check(int[] nums, int x, int maxOperations) {
int count = 0;
// 分割完后,袋子的数量
int m = nums.length + maxOperations;
for (int i = 0; i < nums.length; i++) {
if (nums[i] > x) {
count += (nums[i] + x - 1) / x;
} else {
count++;
}
}
return count <= m;
}
}
复杂度分析
时间复杂度:O(n*log u),n 是 nums 的长度,u是 nums 的最大值。
空间复杂度:O(1)。
标签:right,nums,int,袋子,1760,个球,LeetCode,left From: https://blog.csdn.net/m0_56090828/article/details/137623782