每日一题——袋子里最少数目的球

94 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 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 <= 105
  • 1 <= 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;
    }
}