题目链接
前置知识
- 二分查找
一种高效的查找方法,是用来在一个有序数组中查找某一元素的算法
以数组nums = [1,2,3,4,5,6]为例,我们比较顺序查找和二分查找6的效率- 顺序查找:遍历数组,需要进行
6次的比较 最坏情况下即 - 二分查找:
- 首先定位数组中间
3,6>3那么答案必不在3的左边, 下次从4开始搜索 - 定位
5,此时6>5答案必在5的右边,从6开始搜索 - 定位
6,查找结束 二分查找的复杂度是多少? 每次会减少当前范围的一遍 则为 默认为2为底
- 首先定位数组中间
- 顺序查找:遍历数组,需要进行
从小数据并不能看出二分的效率,但当n足够大且为最坏情况,如n = 1e8,假设比较一个数需要1秒,那么顺序查找需要100000000s 大约需要 1157天才能找到,而二分查找只需要27s
简单实现
nums := []int{1, 2, 3, 4, 5, 6}
target := 6
l, r := 0, len(nums)
for l < r {
mid := l + (r-l)/2
if nums[mid] == target {
fmt.Println("index:", mid)
break
} else if nums[mid] > target {
r = mid
} else {
l = mid + 1
}
}
解题思路
- 简化题意:找到最少评估所有学生的时间,
m名教师评估时间为数组a, 学生有n人 - 考虑,如果我们给一个非常大的时间,比如
t=10000,怎么知道能评估完?
每个教师评估一个学生需要
a[i]分钟,老师是同时工作的,我们目前是t分钟只需要用(小数忽略,因为不够评估一个人), 然后判断评估的人数是否超过了给定的人数
n
- 知道了如何计算在
t分钟内能够评估多少人,考虑如何得到最少时间
当
t分钟满足要求时,那么大于t分钟肯定也是可以的,我们就不需要考虑了,此时答案在[1,t]
此时小于t分钟,评估完和未评估完都可能,我们利用二分的思想去找中间时间假设当前中间时间为
mid如果 mid 评估的人数>=n则答案在左边[1,mid]新一轮
l分钟 ,评估人数小于<n 则答案在右边[l+1,mid]
思路很清晰了,我们考虑评估的上界是多少(最多评估多少分钟)?
n种方法:
1. 评估最慢的老师评估n名学生的时间 必然是合适的值之一
2. 无脑设置一个足够大的数,比如 1e9 0xffffff INT_MAX等,可以根据数据范围制定
3. ....
最少需要多久(下界)?
至少1分钟吧
上下界范围不需要非常明确,只需要保证答案一定在这个范围内即可,但也不能过于离谱
题解代码
func solution(N int, M int, A []int) int {
l,r := 0, 0xfffff
ans :=0
for l < r {
mid := l+(r-l)/2
cnt := 0
for _, v := range A {
cnt += mid / v
}
if cnt >= N {
ans= mid
r = mid
}else {
l = mid + 1
}
}
return ans
}
def solution(N, M, A):
l, r = 0, 0xfffff
ans = 0
while l < r:
mid = l + (r - l) // 2
cnt = 0
for v in A:
cnt += mid // v
if cnt >= N:
ans = mid
r = mid
else:
l = mid + 1
return ans