Codility 测试:你的分数到底衡量了什么
大多数人在 Codidity 测试中以为自己通过了,却实际失败。任务描述中的示例都输出了正确答案,编辑器显示 OK,提交成功——但报告显示只有 40%。原因很简单,值得在参加测试前了解:你看到的示例并不计入得分。
分数实际由哪些部分组成
每道题会在两个独立维度上评分,且会分别展示。
- Correctness — 隐藏测试用例中你的输出与期望相符的比例。每道题至少会运行六个评估用例,你的题目得分是通过的用例所占的百分比。题目描述中展示的示例仅用于演示,并不计入评估。
- Performance — 随着输入规模增长,解法是否仍然满足时间和内存限制。仅在可扩展性计分的题目中适用,即使所有答案都正确,也会对该维度进行评分。
第二个维度往往是人们忽视的。即使在一个以 O(n log n) 为目标的题目中使用了正确的 O(n²) 循环,也能在所有能完成的用例上得到正确答案,却会因为大规模用例超时而失去大部分 Performance 分数。
把约束视作复杂度预算
约束块并非装饰,而是题目告诉你可接受的时间复杂度,它是页面上唯一最有价值的信息。
- N up to 100,000 or more — 任何二次算法都会超时。此时需要使用排序、hash map、two pointers 或 prefix sum 等线性或对数级别的方案。
- N up to a few thousand — O(n²) 通常可以接受,若去追求更巧妙的方案反而会浪费你在其他地方需要的时间。
- Values up to 2 billion — 题目暗示 32 位累加器会溢出。在需要关注整数宽度的语言中,这一点必须考虑。
在动手写代码前先确定目标复杂度。机器评分的测试中,没人会因为你有良好的直觉却未实现而给你加分。
分数到底流向哪里
三种模式导致了大部分分数流失,而且它们都与算法能力无关。
- 没有人测试的边界情况。 空输入、单个元素、所有元素相等、最小和最大允许值。这些正是隐藏用例,因为它们是最容易写的。
- 边界的 off-by-one 错误。 包含式与排除式区间比任何数据结构都更容易扣掉 Codility 分数。
- 第三题超时。 计时器覆盖整个测验,而不是每道题单独计时。把可运行的暴力解法留在每道题上的人,通常会比只有一个完美解法而另外两题空白的人得分更高。
部分得分是真实的,务必利用它
因为得分是按用例比例计算的,诚实的暴力解法比空编辑器价值高得多。在时间压力下得分最高的顺序几乎总是相同的:先写出显而易见的解法并提交,然后再优化并再次提交。先拿到分数,再去提升。
如果你知道自己的解法太慢且无法改进,就直接保留它。对大用例超时的提交仍然会收集所有通过的小用例和中等用例的分数。
最后的十分钟
停止编写新代码。对每道题分别使用空输入、单个元素以及约束允许的最大值各运行一次。这样一次通过比对困难题的第四次尝试获得的分数更多,而且只需三分钟。
还有一点值得事先了解,而不是事后才发现:平台会记录标签页中的所有操作,包括焦点切换和粘贴的代码块,雇主会在你的分数旁看到这些摘要。把测试安排成一次坐下来完成的过程,而不是从其他窗口拼凑而成。
FAQ
任务中的示例会计入我的 Codility 分数吗?
不会。题目中的示例仅用于说明。你的分数是你通过的隐藏评估测试用例的百分比,这也是即使你的代码能处理所有给出的示例,分数仍可能很低的原因。
什么算是及格的 Codility 分数?
没有统一的及格线——由雇主自行设定。实际中,大多数公司会查看所有任务的总百分比,以及你的性能分数是否表明你理解了预期的复杂度。
我可以返回之前的任务吗?
在大多数 Codility 测试配置中可以,整个测试共用一个计时器,你可以在计时结束前在任务之间切换。这正是为什么先提交一个暴力解法再返回进行优化如此有效的原因。
Codility 会检测标签切换或粘贴代码吗?
平台会记录焦点切换和大段粘贴,并将这些信息连同分数一起报告给雇主。它不会自动让你失败,但报告的摘要对查看报告的人是可见的。