文章目录
-
- [1. 题目来源](#1. 题目来源)
- [2. 题目解析](#2. 题目解析)
1. 题目来源
题单:
- 待补充
2. 题目解析
思路:
- 看题意求最大、最小,很明显的二分答案,直接去二分满足条件下的最终袋子中球的个数。
- 二段性思考 :
- 如果最终袋子中球都是 1 个的话,那么袋子肯定很多,操作次数就非常多。
- 如果最终袋子中球都可以装很多的时候,那么一开始都不用二分,操作次数就是 0。
- 故,二分的边界点就是这个操作次数。那么操作边界就是最终袋子中能装的球的个数,即
[1, max{nums[0~n-1]}
。
- 操作次数思考:
- 如果二分答案袋子中的球至多可装 y 个情况下。
- 那么原有袋子球在
[1,y]
的操作次数是 0,在[y+1, 2y]
的操作次数是 1。 - 数学归纳来看,nums[i] 的操作次数就是 n u m s [ i ] − 1 y {\frac{nums[i]-1}{y}} ynums[i]−1
综上,本题实际上不是很难,值得一提的是:
- 关于这个操作次数的推导,可以看看灵神那边针对边界、针对上取整、下取整的数学推导,更为严谨。可以看看官解中针对 1~y、y+1 ~2y 这种分段的判断,更为直观。
- 最近拿 GoLang 写算法,比如二分,比如求 slice 中的最大元素,都有现成的库函数待学习。见这个博主的博文整理,挺不错的:【Go基础】Go算法常用函数整理
坑点:
- C++ 选手记得开 long long 不然会爆...
- [1000000000,1000000000,1000000000]
1000000000
这个数据,最终结果是 3,但 cnt 的累计就很多很多超过 int 上限了...
- 时间复杂度 : O ( n ) O(n) O(n)
- 空间复杂度 : O ( 1 ) O(1) O(1)
go
func minimumSize(nums []int, maxOperations int) int {
check := func(k int) bool {
cnt := 0
for _, v := range nums {
cnt += (v - 1) / k
}
return cnt > maxOperations
}
l, r := 1, slices.Max(nums)
for l < r {
mid := (l + r) / 2
if check(mid) {
l = mid + 1
} else {
r = mid
}
}
return l
}
库函数写法:
go
func minimumSize(nums []int, maxOperations int) int {
max := 0
for _, x := range nums {
if x > max {
max = x
}
}
return sort.Search(max, func(y int) bool {
if y == 0 {
return false
}
ops := 0
for _, x := range nums {
ops += (x - 1) / y
}
return ops <= maxOperations
})
}