Codeforces 768A:Python代码第10测试点WA问题排查
题目描述
“长夜将至,我从今开始守望,至死方休。我将不娶妻、不封地、不生子。我将不戴宝冠,不争荣宠。我将尽忠职守,生死于斯。我是黑暗中的利剑,长城上的守卫,抵御寒冷的烈焰,破晓时分的光线,唤醒眠者的号角,守护王国的坚盾。我将生命与荣耀献给守夜人,今夜如此,夜夜皆然。”——守夜人誓词。
琼恩·雪诺的守望自此开始,他被分配的任务是为事务官提供支援。
他手下共有n名事务官需要提供支援,每名事务官有对应的力量值。只有当存在至少一名力量值严格小于他、且至少一名力量值严格大于他的事务官时,琼恩才会为该事务官提供支援。
请计算琼恩总共会为多少名事务官提供支援?
问题排查
你一开始的解题方向完全正确:答案就是所有力量值既不等于全局最小值、也不等于全局最大值的事务官总数。但代码存在两个问题,其中一个是直接导致测试点报错的致命逻辑错误:
- 核心bug:你用集合推导式
{i for i in a}生成去重列表b,但Python原生集合是无序结构,哪怕你之前对a排过序,转集合之后元素顺序会被打乱,再转成列表时,b[0]不一定是全局最小值,b[-1]也不一定是全局最大值。前9个测试点能通过只是小数据下集合顺序刚好和你预期一致,碰到数据分布特殊的测试点,代码会错误删除非最值元素,或者漏删最值元素,自然返回错误结果。 - 效率缺陷:反复调用
list.remove()每次都要从头遍历列表匹配元素,整体时间复杂度是O(n²),碰到n较大的测试点很容易超时。
原错误代码如下:
n = input() a = list(map(int, input().split())) a.sort() b = list({i for i in a}) while b[0] in a: a.remove(b[0]) # removes the smallest value while b[len(b)-1] in a: a.remove(b[len(b)-1]) # removes the largest value print(len(a))
修正方案
完全不需要额外生成去重列表,直接调用内置函数取全局最小值和最大值,遍历一次列表统计符合条件的元素即可,时间复杂度为O(n),可以覆盖所有数据范围,同时能自动覆盖边界场景:比如所有元素值相同、总人数小于3时,结果自然为0。
修正后可通过所有测试点的代码:
n = int(input()) a = list(map(int, input().split())) min_val = min(a) max_val = max(a) count = 0 for num in a: if min_val < num < max_val: count += 1 print(count)
内容的提问来源于stack exchange,提问作者Vesal E.a
相关产品推荐
相关产品推荐

