解题思路:
看了很久也不知道该怎么下手,果断转去题解看答案,所实话官方的题解说的有些抽象,先买那是我自己看了别人的博客和思考后的一些思路:
1、为什么可以用二分查找?
题目要求你的开销是单个袋子里球数目的 最大值 ,你想要 最小化 开销。也就是获取这个最小值即可,可以很明显的知道这个值位于1~nums[i]的最大值之间,所以完全可以使用二分查找来寻找这个值,假设这个值是mid,如果符合条件的话,则继续寻找[1~mid]并不断更新,如果mid不满足条件的话则去区间[mid+1~max_element]之间寻找。
2、如何判断mid是否满足条件?
最多操作m次,假设当前二分查找到了mid,那么如果正向思考,我们去分割 m 次,最小开销是否小于等于 mid, 这样思考会比较难想,那么我们尝试去反过来思考,我们直接将每个袋子都分成<=mid,最后判断操作次数是否 <=m即可。 这里的思路借鉴了该篇博客
那么操作次数如何获取,即只要遍历nums数组,对于每个nums[i]需要次(其中⌊x⌋ 示将x进行下取整)。解释是官方题解上的,这里照搬过来:
- 当nums[i]<=mid时,我们无需进行操作;
- 当mid<nums[i]<=2mid时,我们需要进行 11 次操作;
- 当2mid<nums[i]<=3mid时,我们需要进行 22 次操作;
- ……
ok剩下就是代码的事了,相信你看到这里官方的题解以及一些个人的题解都能看得明白了。
class Solution:
def minimumSize(self, nums: List[int], maxOperations: int) -> int:
left, right, ans = 1, max(nums), 0
while left <= right:
mid = (left + right) // 2
# 这里ops即为算出来的需要的操作次数,来判断该mid是否可行
ops = sum((x - 1) // mid for x in nums)
if ops <= maxOperations:
ans = mid
right = mid - 1
else:
left = mid + 1
return ans