力扣-袋子里最少数目的球 从问题出发了解二分查找——力扣·百战炼磨(二)

2021/4/16

力扣第228场周赛——虚拟竞赛

第三题 袋子里最少数目的球

力扣 1760


二分搜索

解决问题部分常见的方法之一

说真的,当他拿去找答案时,这个想法真邪门


一、二分搜索是什么?

二分查找是一种高效的搜索方式,其复杂度为 log2(n)。


# 二、二分搜索怎么做? 二分查找是一种高效的搜索方式,我们假设一个升序排列的元素组,将要查找的元素于元素组正中间的元素比较,进行以下三重情况的处理
  1. 若相等则返回该元素
  2. 若小于则将开始到该元素作为下一次二分搜索的数组
  3. 若大于则将该元素到结束作为下一次二分搜索的数组

直到找到。


三、力扣经典题——袋子里最少数目的球

我们从一道经典问题出发来帮助我们理解这个说法:

	给你一个整数数组 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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-limit-of-balls-in-a-bag
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。


分析题目:
该题目要求我们找出在n次操作后,最多球的袋子里的球尽可能少。

每次操作效果为将一个袋子里的球按任意分发分到两个新袋子中。

给定一个数,在少于这个数的次数的操作下所可能的最小值。

  1. 由分析可知,在n次操作下,可以将一个袋子中的球分成:球总数/n;
  2. 则可以转换为判定问题:设单个袋子球的最大数目为y,当一个袋子分n次可以完成这个目标,求n。
  3. 然后我们将袋子推广到所有袋子,及:将y设为所有袋子中单个袋子球的最大数目为y,然后对每个袋子都这样考虑,并将n加起来,如果加起来n小于他所给的数,则这个y为可能的最小值。

而如何找到这个y呢?我们将之前的二分搜索带入考虑。

注意:
在操作次数增加的情况下,y是一定减少的,在操作次数减少的情况下,y一定是增加的。

所以他们是单调关系,这种情况下,y的可能的答案是一个单调数组,因为这个前提条件,我们可以使用二分搜索来搜索答案。

说真的,对于初学者这可能有点超越想象


以下为力扣用户 zerotrac写出的题解:
	class Solution {
	public:
	    int minimumSize(vector<int>& nums, int maxOperations) {
	        int left = 1, right = *max_element(nums.begin(), nums.end());
	        int ans = 0;
	        while (left <= right) {
	            int y = (left + right) / 2;
	            long long ops = 0;
	            for (int x: nums) {
	                ops += (x - 1) / y;
	            }
	            if (ops <= maxOperations) {
	                ans = y;
	                right = y - 1;
	            }
	            else {
	                left = y + 1;
	            }
	        }
	        return ans;
	    }
	};

作者:zerotrac2
链接:https://leetcode-cn.com/problems/minimum-limit-of-balls-in-a-bag/solution/dai-zi-li-zui-shao-shu-mu-de-qiu-by-zero-upwe/
来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

首先答主设计了答案区,从1到数组最大值,
之后在该区域内进行二分搜索,每次对“完成y为目标的总次数”的判断:

  1. 如果符合,则返回y。
  2. 如不符合,则在大于或小于的情况中选择并进行下一次判断。

其中zerotrac的核心部分为对y的搜寻,并在函数最后返回搜索到的答案。


总结

本人还只是一个小学生,才疏学浅,还希望大家能多多包涵,有什么不足请大家指正。
如果这篇文章帮到你请帮忙点个赞让我看到,谢谢大家抬爱。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值