每日一题_1894. 找到需要补充粉笔的学生编号
题意分析
今天教师节,然后leetcode就很应景的整了个这个题
通过读题,该题的意思是说,有n个学生,这n个学生轮流上黑板做题(确定做题?这么多粉笔都可以把黑板涂满了),做题会用粉笔,每个学生上去做题用的粉笔不一样,但都是定值,用一个数组来表示,然后粉笔盒里有k支粉笔。这n个学生就一直轮流上去做题,直到把粉笔盒里的k支粉笔用完,然后轮到最后的那个学生会因为粉笔不够而没法做题,题目就是让我们返回这个最后的学生的编号。
分析完题意后最直接的想法既然轮流做题,那么我们可以用 i 表示学生来模拟,到了超过 n 的时候模 n,这样就表示新的一轮,每次都将k减去花掉的粉笔,这样模拟知道 k 小于当前学生所花的粉笔,但是一看数据要求 n 最大10^5,k 最大10 ^9,这样模拟时间复杂度肯定会炸。
继续思考,其实我们只关注最后一个,其实一轮下来学生所花的粉笔是定值,那么我们用k对一轮所花的粉笔取余,就得到了我们最后一轮粉笔不够时的数量,然后去模拟,这样就不会炸了。
再思考一下,其实每个学生上去一次,花费的粉笔的数量就会累加,直到超出粉笔盒粉笔的数量,那么针对最后一轮,其实我们就是在找何时累加的粉笔数量到达临界点,就是加上这个学生数量就会超过粉笔盒内粉笔的数量。这中累加的情况,我们就会想到前缀和,然后找这中临界点(边界),临界点的一边满足条件,边界点的另一边不满足条件。这是就应想到二分。综上分析,最终采用的算法就是 前缀和 + 二分 来解决。
代码:
int chalkReplacer(vector<int>& chalk, int k) {
int n = chalk.size();
vector<long long> s(n + 1, 0);
for (int i = 1; i <= n; i ++) s[i] = s[i - 1] + chalk[i - 1];
long long remain = k % s[n];
int l = 1, r = n;
while (l < r)
{
int mid = l + r >> 1;
if (s[mid] > remain) r = mid;
else l = mid + 1;
}
return l - 1;
}
};