学生消耗粉笔的过程是重复的。记每一轮消耗粉笔的总量为 total,它等于数组 chalk 的元素之和。因此,我们可以将粉笔数量 k 对 total 进行取模,求得余数 k’ 以方便后续计算。由于 k’ 一定小于 total,因此我们只需要至多遍历一遍数组 chalk,同时模拟 k’ 减小的过程,即可以得到需要补充粉笔的学生编号。
细节
由于 total 可能会超过 32 位有符号整数的范围,因此对于一些整数类型有范围的语言,为了避免溢出,需要使用 64 位整数存储 total。
代码
[sol1-C++]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
classSolution { public: intchalkReplacer(vector<int>& chalk, int k){ int n = chalk.size(); longlong total = accumulate(chalk.begin(), chalk.end(), 0LL); k %= total; int res = -1; for (int i = 0; i < n; ++i) { if (chalk[i] > k) { res = i; break; } k -= chalk[i]; } return res; } };
[sol1-Java]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
classSolution { publicintchalkReplacer(int[] chalk, int k) { intn= chalk.length; longtotal=0; for (int num : chalk) { total += num; } k %= total; intres= -1; for (inti=0; i < n; ++i) { if (chalk[i] > k) { res = i; break; } k -= chalk[i]; } return res; } }
publicclassSolution { publicintChalkReplacer(int[] chalk, int k) { int n = chalk.Length; long total = 0; foreach (int num in chalk) { total += num; } if (k >= total) { k %= (int) total; } int res = -1; for (int i = 0; i < n; ++i) { if (chalk[i] > k) { res = i; break; } k -= chalk[i]; } return res; } }
[sol1-Python3]
1 2 3 4 5 6 7 8 9 10 11
classSolution: defchalkReplacer(self, chalk: List[int], k: int) -> int: total = sum(chalk) k %= total res = -1 for i, cnt inenumerate(chalk): if cnt > k: res = i break k -= cnt return res
[sol1-JavaScript]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
var chalkReplacer = function(chalk, k) { const n = chalk.length; let total = 0; for (const num of chalk) { total += num; } k %= total; let res = -1; for (let i = 0; i < n; ++i) { if (chalk[i] > k) { res = i; break; } k -= chalk[i]; } return res; };
[sol1-Golang]
1 2 3 4 5 6 7 8 9 10 11 12 13 14
funcchalkReplacer(chalk []int, k int)int { total := 0 for _, v := range chalk { total += v } k %= total for i, c := range chalk { if k < c { return i } k -= c } return0 }
复杂度分析
时间复杂度:O(n),其中 n 是数组 chalk 的长度。我们最多遍历数组 chalk 两次,第一次求出粉笔的总量 total,第二次找出答案。
funcchalkReplacer(chalk []int, k int)int { if chalk[0] > k { return0 } n := len(chalk) for i := 1; i < n; i++ { chalk[i] += chalk[i-1] if chalk[i] > k { return i } } k %= chalk[n-1] return sort.SearchInts(chalk, k+1) }
复杂度分析
时间复杂度:O(n),其中 n 是数组 chalk 的长度。计算前缀和的时间复杂度为 O(n),二分查找的时间复杂度为 O(\log n),因此总时间复杂度为 O(n)。