Python数据类型易错点详解:计算机能力挑战赛避坑指南
每年带学生准备计算机能力挑战赛赛后答疑几乎都会变成同一场事故复盘题面读懂了算法也写出来了提交之后却是WA或者RE最后逐行对才发现问题全出在数据类型上。这类比赛不像平时的课后练习输入规模更大、评测数据更刁钻Python里那些平时感觉没啥、考试才出事的边界行为就会在多个测试点里集中引爆。这篇文章我想把Python数据类型相关的易错点和难理解内容一次性讲透按40个最常见的新手雷区来组织。它不是一本语法手册而是我在真实比赛环境里反复踩过、也在学生代码里反复看到的坑。无论你是准备参加计算机能力挑战赛还是想在笔试面试前快速过一遍Python内建类型这份整理都能直接当复习资料用每个点都给了结论、原因和规避方式。1. 为什么计算机能力挑战赛总在数据类型上扣分1.1 这些坑为什么平时不踩、比赛才爆课后练习的用例往往比较温和输入范围小边界条件少。比赛则不同同一道题可能有几十个测试点专门覆盖边界值、负数和极端输入。你本地跑样例全过不代表代码在边界数据下还正确。数据类型问题最大的特点是隐蔽——不报语法错误不抛异常就是结果不对。比如整数除法向负无穷取整、浮点数的二进制精度损失、列表的引用共享这些在常规小例子里根本看不出来一旦数据量上去直接变成WA或者TLE。还有一个现实因素很多新手在备赛时把精力全放在算法模板上背了一堆BFS、DP、二分模板却忽略了Python内建类型本身就是一门考点。而竞赛题里的排序、去重、哈希、文本处理本质都是在和数据类型打交道。1.2 40个易错点怎么分布为了不让你像无头苍蝇一样乱翻我先把整篇文章的雷区分布画成一张表后面每个章节都会按编号逐个拆解。章节主题易错点编号第2节整数、浮点、布尔1-8第3节字符串与字节9-17第4节列表、元组与引用18-28第5节字典与集合29-35第6节类型判断与转换36-40我筛选这些点的标准很简单要么在真实比赛中造成过扣分要么是新手理解上特别容易拧巴的概念。所有例子我都用最精简的代码验证过你可以直接复制到本地跑一遍。1.3 建议的阅读方式如果你是第一次系统过顺序读每个点都亲自敲一遍代码尤其是标了实测结果的片段。如果你马上要比赛重点看第4节和第5节——引用和哈希这两块是WA和TLE的高发区。如果你只是临时查漏直接用编号快速定位。我不建议跳着看因为很多点之间是互相解释的比如列表浅拷贝会牵扯到嵌套初始化字典可哈希性又和元组有关。2. 数字三兄弟的八宗罪整数、浮点与布尔易错点1-8数字类型是新手最不在意、比赛最常埋雷的板块。原因很简单小学就学过算术谁会觉得自己不会用数字但Python的数字有一堆反直觉行为下面这八个点每一个我都亲眼见过翻车现场。2.1 整除和取模的符号方向易错点1//是向下取整不是向零截断。print(-3 // 2) # 结果是 -2不是 -1 print(3 // -2) # 结果是 -2C、Java里整数除法是向零截断-3/2得到-1。Python的//则是向下取整得到-2。这个差异在坐标处理、分页计算、环形数组索引里特别致命。比如你要把负数坐标映射到数组下标如果直接x // n负数方向就错了。要保证结果非负正确做法是(x % n n) % n。易错点2取模运算的结果符号跟随右操作数除数。print(-3 % 2) # 结果是 1 print(3 % -2) # 结果是 -1这个和//是配套的因为Python要求a (a // b) * b a % b恒成立。-3 // 2是-2那么-3 % 2必须是1。记住这个等式比死记符号规则靠谱得多。比赛里做循环位移时我经常用index % n如果index可能是负数一定要先转正再取模。2.2 浮点精度的三连坑易错点30.1 0.2 ! 0.3。print(0.1 0.2 0.3) # False print(0.1 0.2) # 0.30000000000000004这不是Python的bug而是二进制浮点数无法精确表示十进制小数的必然结果。计算机用二进制存小数很多十进制小数是无限循环二进制只能截断存储。比赛里如果题目要判断浮点是否相等绝对不能用要用abs(a - b) 1e-9或者直接用math.isclose(a, b, rel_tol1e-9)。易错点4大整数和浮点混在一起比较时精度会悄悄丢失。print(2 ** 53 1 2 ** 53) # 在浮点参与比较时可能为 TruePython的int是任意精度的但一旦和float比较int会被转成float再比而float只有53位尾数精度。超过2**53的整数相邻整数在float眼里是同一个数。比赛里如果涉及超大数值的大小比较要么全部用int要么改用decimal.Decimal别让float半路插一脚。易错点5round()是银行家舍入不是四舍五入。print(round(0.5)) # 0不是1 print(round(2.5)) # 2 print(round(2.675, 2)) # 2.67不是2.68round()的规则是四舍六入五成双恰好落在中间时舍入到最近的偶数。再加上浮点本身的精度问题round(2.675, 2)的结果是2.67。比赛里如果要求四舍五入保留两位小数千万别直接用round老老实实先放大再取整或者用Decimal配合ROUND_HALF_UP。2.3 bool的隐藏身份与位运算优先级易错点6bool是int的子类True和False可以直接参与算术。print(True True) # 2 print(True 1) # True print(sum([True, False, True])) # 2 print(isinstance(True, int)) # True这个点本身不算坑但很有迷惑性。你要是想用if x is True判断会发现x 1的时候不匹配而isinstance(x, int)对True也返回True。比赛中用sum统计满足条件的数量时sum(x 0 for x in arr)这种写法能少写好几行前提是你理解它为什么能work。易错点7移位运算优先级低于加减法1 2 3不等于8。print(1 2 3) # 结果是 32而不是 8Python里的优先级高于所以1 2 3被解析成1 (2 3)。做位运算优化时我建议任何混合表达都加上括号不给自己留读代码的坑。类似的还有、|和比较运算混用的场景加了括号逻辑一目了然也不会因为Python版本解析差异吃闷亏。2.4 大整数与进制转换易错点8int不溢出的好事背后也藏着性能和进制坑。Python的int是任意精度这比C系语言友好太多但也不是没有代价。超大的整数运算在循环里会明显变慢另外int()转换带进制参数时规则和很多人想的不一样print(int(ff, 16)) # 255 print(int(0x10, 16)) # 16允许带前缀 print(int(10, 0)) # 10base0时自动识别前缀 print(int(1.2)) # ValueError这个字符串没法直接转int比赛里读十六进制、二进制数据时int(s, base)是标准做法。但注意int不接受含小数的字符串要先用float()或者干脆避免这种转换。3. 字符串第二个扣分重灾区易错点9-17字符串在竞赛里的出镜率极高回文判断、词频统计、文本清洗全是字符串。而且字符串类型有三个特点不可变、索引切片规则多、和字节流纠缠不清每一个单拎出来都能写一篇踩坑笔记。3.1 不可变性决定你的拼接方式易错点9循环里用拼接字符串是O(n²)操作。s for i in range(100000): s str(i) # 每次循环都创建新字符串整体很慢字符串是不可变对象每次s x都会把原来的字符串整体拷贝一遍再生成新的。循环n次总代价是123...n也就是O(n²)。数据量小没事上了十万级别直接TLE。正确做法是把片段收集到list最后用.join(lst)一次性拼接。我在比赛里写输出时也习惯先把所有行放进list最后统一\n.join(lines)能省下大量IO时间。3.2 切片、strip和split的边界行为易错点10切片越界不报错索引越界才报错。s abcdef print(s[100:]) # 空字符串不报错 print(s[100]) # IndexError这是个特别容易记混的点。切片操作天生宽容超出范围就返回空或者截断而单索引访问超出范围直接抛异常。做防御性代码时如果不知道字符串够不够长用切片取尾部是安全的用索引取就必须先判长度。另外[::-1]是字符串反转的经典写法但负步长切片的起止位置理解起来有点绕s[5:0:-1]取的是从5到1不包含0需要自己多跑几次验证。易错点11split()和split( )是两套逻辑。s a b c print(s.split()) # [a, b, c]连续空白自动合并 print(s.split( )) # [a, , b, , , c]按单个空格切不带参数的split()会按任意空白字符切分包括空格、制表符、换行而且连续空白只算一次。这在读取列数不固定、空格数量不统一的文本时非常方便。比赛里读取一行数字直接input().split()是最省心的别画蛇添足传空格参数。易错点12strip()的参数是字符集合不是子串。print(banana.strip(ab)) # nan两端所有a和b都被去掉 print(hello.txt.removeprefix(hello).removesuffix(.txt))strip(ab)会把两端所有字符a和b都剥掉而不是剥掉字面量ab。想精确去掉前缀后缀Python 3.9以上有removeprefix和removesuffix语义清晰得多。老版本就用切片判断if s.startswith(...)。3.3 字符串比较、格式化与字符转换易错点13字符串按字典序比较不是按数字大小。print(10 9) # True因为 1 的码点小于 9比较两个字符串比较的是逐字符的Unicode码点所以10排在9前面。从文件里读出来的数字全是字符串直接排序会得到[1, 10, 2, 9]这种假顺序。比赛里要按数字排序必须keyint。另外大小写敏感的坑也要注意A的码点小于a大写字母整体排在小写前面。易错点14换行符不是只有\n一种。Windows文件里换行是\r\n老Mac是\r。用input()读行会自动去掉末尾换行符但用sys.stdin.readline()读回来的字符串末尾带着\n如果你不处理直接参与比较就会莫名WA。更稳妥的做法是每行rstrip(\n)或者直接用splitlines()——它能同时处理\n、\r\n和\r。易错点15三种格式化方式别混着乱用。%s、str.format和f-string各有适用场景。f-string在Python 3.6以上最好用性能也好直接在字符串里写表达式最直观。format的优势是模板复用可以先定义模板再填充不同数据。格式化浮点数时f{x:.2f}的舍入规则和round一样要注意它用的是浮点数的二进制表示而不是十进制精确值。批量输出时我习惯先用列表推导生成格式化后的字符串再统一join。易错点16ord()和chr()是字符和码点之间的桥。print(ord(a)) # 97 print(chr(97)) # a print(ord(A)) # 65注意大小写字母差32做字母相关题目时ord(ch) - ord(a)能把字符映射成0-25的数组下标这是哈希计数的基础。反之chr(ord(a) i)能按顺序生成字母。这个点本身不复杂但很多新手第一次用的时候容易把ord和chr搞反或者忘了A和a之间差了32而不是26。3.4 字节与编码易错点17bytes和str不是一个类型混用就TypeError。bhello world # TypeError: cant concat str to bytesstr是Unicode字符序列bytes是字节序列。读取二进制文件、处理网络数据时拿到的是bytes要转成文本必须decode(utf-8)反过来文本转字节用encode(utf-8)。还有一个细节遍历bytes得到的是整数不是单个字符。list(babc)是[97, 98, 99]。比赛里如果从二进制流读数据千万别假设它是str直接拼接替换。4. 列表与元组可变性与引用的九连环易错点18-28列表是竞赛代码的主力容器但也正因为太常用大家对它的可变性和引用机制反而理解最浅。这一节的坑本质都是同一个问题你以为在操作值其实在操作引用。4.1 三种复制的区别易错点18b a不是拷贝只是多了一个名字。a [1, 2, 3] b a b.append(4) print(a) # [1, 2, 3, 4]a也跟着变了这是新手最常见的认知偏差。列表是可变对象b a只是让b指向同一个列表对象。想要独立的副本用a[:]、a.copy()、list(a)都行。但注意这些都是浅拷贝。易错点19浅拷贝只复制一层嵌套列表照样共享。a [[1, 2], [3, 4]] b a.copy() b[0].append(99) print(a) # [[1, 2, 99], [3, 4]]内层还是同一个copy()和切片都只复制最外层内层列表的引用原封不动。要完全独立用copy.deepcopy(a)。但比赛里一旦数据量大deepcopy的性能开销很吓人。更聪明的做法是手动构造深层副本[row[:] for row in a]只复制需要的那一层。4.2 嵌套列表初始化的经典车祸易错点20[[0] * n] * m创建的每一行都是同一个对象。grid [[0, 0, 0]] * 3 grid[0][0] 1 print(grid) # [[1, 0, 0], [1, 0, 0], [1, 0, 0]][0] * n没问题因为0是不可变整数重复创建的都是同一个0但改不了。而[[0] * n] * m是把同一个列表对象复制了m次引用你改其中一行所有行都跟着变。正确写法是列表推导式grid [[0] * n for _ in range(m)]每次循环都新建一个列表各行才真正独立。4.3 增删元素时的索引位移易错点21append添加一个元素extend展开一个可迭代对象。a [1, 2] a.append([3, 4]) # [1, 2, [3, 4]] a.extend([3, 4]) # [1, 2, 3, 4]append把参数当成一个元素塞进去extend则把参数里的每个元素逐个追加。用拼接列表会创建新列表和extend的原地修改是不同的。比赛里要收集多行数据extend和的语义要分清楚。易错点22正序遍历删除元素会跳过倒序或者用推导式过滤才安全。nums [1, 2, 3, 4, 5] for x in nums: if x % 2 0: nums.remove(x) # 删掉2后3被跳过结果不对remove删除第一个匹配项同时后面的元素整体前移for循环的索引却还在往前走于是跳项。要删多个符合条件的元素最干净的是列表推导式重建nums [x for x in nums if x % 2 ! 0]。如果必须原地删就倒序遍历for i in range(len(nums) - 1, -1, -1)这样删除当前索引不会影响前面未访问的位置。4.4 排序的稳定性和key设计易错点23list.sort()原地修改并返回Nonesorted()返回新列表。a [3, 1, 2] b a.sort() # b是None c sorted(a) # c是排序后的新列表很多人写a a.sort()结果a变成None。sort()是原地排序千万别把返回值赋给变量。顺便说一句sort(keylen)按长度排、sort(keylambda x: -x)降序排这些key设计比写一堆比较函数高效得多。易错点24sort是稳定排序多条件排序用key返回元组。words [banana, apple, cherry, blueberry] words.sort(keylambda x: (-len(x), x)) # 先按长度降序长度相同再按字典序升序Python的sort稳定意味着相等元素保持原相对顺序。多条件排序不用写复杂比较函数key返回一个元组即可元组从左到右逐项比较。这个技巧在处理先按频率降序、再按内容字典序这类题时是标准解。4.5 切片、负索引与推导式易错点25列表切片越界返回空列表索引越界抛异常。和字符串一样arr[100:]返回[]但arr[100]抛IndexError。写二分查找、滑动窗口时取子数组用切片很安全取单个元素前一定先确认长度。易错点26负索引从右边数[-1]是最后一个[-0]是第一个。-1是倒数第一个元素-2是倒数第二个这个大家熟。但-0就是0Python里没有负零索引arr[-0]取到的是第一个元素。这个小知识点经常在面试手写代码时被拿来当陷阱问比赛里倒是少见但理解负索引的统一规则arr[-i]等价于arr[len(arr)-i]对写代码有好处。易错点27列表推导式的嵌套顺序是从左到右和for循环一致。pairs [(x, y) for x in range(3) for y in range(3)]它等价于两层for循环左边是外层右边是内层。如果要加条件过滤位置不同含义不同放在for ... if ...之间是内层过滤放在最前面是后置过滤。写复杂推导式前先在脑子里展开成普通循环确认一遍能省下debug时间。4.6 元组的括号和不可变性易错点28(1)是整数(1,)才是元组。print(type((1))) # class int print(type((1,))) # class tuple单元素元组必须有那一个逗号括号只是语法结构。元组本身不可变但如果元组里放了列表那个列表的内容还是可以变的。所以元组不可变要精确理解成元组的元素引用不可变。另外元组可以作为字典键列表不行这点往下看。5. 字典与集合哈希世界的潜规则易错点29-35字典和集合在比赛里是用空间换时间的核心工具。它们底层都基于哈希表所以可哈希性和遍历时修改这两个问题是这节的重点。5.1 键的资格可哈希性易错点29列表、字典和集合都不能当字典键因为它们不可哈希。d {} d[[1, 2]] x # TypeError: unhashable type: list哈希要求对象在其生命周期内哈希值不变所以必须不可变。int、str、tuple、frozenset可以当键。比赛里如果要把一个坐标对存进字典(x, y)这个元组就是键如果想把一个列表去重并统计次数得先把列表转成元组tuple(lst)。还有一个容易忽略的点float可以当键但精度问题可能导致明明相等的两个值哈希不同或者浮点误差导致查不到。我在比赛里一律避免用float做键要么转成整数缩放要么转成字符串。5.2 默认值三兄弟易错点30get、setdefault和defaultdict各有各的用场。d {} print(d.get(count, 0)) # 0不修改原字典 d[count] d.get(count, 0) 1 d.setdefault(key, []).append(1) # 键不存在时设置默认值 from collections import defaultdict dd defaultdict(int) dd[a] 1 # 不存在自动初始化为0 dd2 defaultdict(list) dd2[group].append(item)get是安全的读不会往字典里塞新键setdefault是取不到就设一个默认值的写操作适合deque、list这类需要初始化的容器defaultdict则在统计和分组场景里最省心。注意defaultdict(int)统计词频时不存在的键自动是0直接 1就行。5.3 遍历修改与字典合并易错点31遍历字典时直接增删键会抛RuntimeError。d {a: 1, b: 2} for k in d: d.pop(k) # RuntimeError: dictionary changed size during iteration遍历过程中字典的size一旦变化迭代器直接罢工。要过滤字典最优雅的是字典推导式{k: v for k, v in d.items() if v 0}生成新字典不影响原字典。如果要原地删先把键收集到列表for k in list(d.keys()): ...遍历的是副本删除的才是原字典。易错点32字典合并三种写法版本兼容性是关键。a {x: 1} b {y: 2} a.update(b) # 原地合并所有版本通用 c {**a, **b} # 生成新字典3.5可用 d a | b # 3.9才支持老OJ会报语法错误很多在线评测系统还跑在Python 3.8甚至更早版本|合并运算符直接就是语法错误。比赛前先确认评测环境版本。我自己的习惯是{**a, **b}兼顾新老版本语义也清晰。5.4 O(1)判重的真实价值易错点33列表 in是O(n)集合 in是O(1)。arr list(range(100000)) queries list(range(100000)) # 用 list 判重每个查询都要遍历整个列表总复杂度 O(n^2) for q in queries: if q in arr: pass # 用 set总复杂度 O(n) s set(arr) for q in queries: if q in s: pass这是TLE最常见的来源之一。很多新手习惯用list存数据然后在循环里if x in lst。数据量小没事一旦n到十万O(n²)直接超时。记住凡是涉及某个元素是否存在重复次数的题第一反应应该是set或dict。易错点34set去重结果不保证顺序frozenset可以作为字典键。lst [3, 1, 2, 1, 3] print(list(set(lst))) # 顺序是任意的可能 [1, 2, 3]set的内部存储依赖哈希输出顺序无法预测。如果既要保持原顺序又要去重用list(dict.fromkeys(lst))——字典键天然去重同时保留第一次出现的顺序这个技巧在比赛里非常实用。另外普通set不能放进另一个set做键需要frozenset。易错点35Counter是词频统计的最短路径。from collections import Counter words [a, b, a, c, b, a] cnt Counter(words) print(cnt) # Counter({a: 3, b: 2, c: 1}) print(cnt[z]) # 0不存在的键返回0不抛异常 print(cnt.most_common(2)) # [(a, 3), (b, 2)]手动统计词频用defaultdict也行但Counter提供了most_common这个方法按频率排序一步到位。它返回的列表可以直接配合排序和多条件key使用。注意Counter访问不存在的键返回0不会抛出KeyError这个和普通字典不一样。6. 类型判断与转换从WA到AC的最后一道关卡易错点36-40数据从输入到处理中间全是类型转换。很多WA不是算法错而是数据在转换边界上出了岔子。6.1 type和isinstance选错直接翻车易错点36isinstance支持继承关系type(x) is T只匹配精确类型。print(isinstance(True, int)) # True因为bool是int的子类 print(type(True) is int) # False如果你要精确判断这个对象是不是int类型type(x) is int更严格如果你要判断能不能当int用isinstance(x, int)更有包容性。还有一个隐藏坑type(x) int和type(x) is int几乎等价但在涉及代理类型时可能出幺蛾子is更稳。比赛里绝大多数情况下用isinstance就够但涉及bool时一定想清楚你到底要不要把True也算进去。6.2 int与float转换的边界易错点37int()和float()的输入规则完全不同。int(1.2) # ValueError整数转换不接受小数点 int(1.2) # 1浮点转整数直接截断 float(1e3) # 1000.0科学计数法字符串可以转 int(ff, 16) # 255带进制参数可以解析 int(0x10, 16) # 16能识别0x前缀从字符串转int字符串里必须真的是整数格式1.2直接报错。从float转int则是向零截断不是四舍五入。这个点看着基础但在读入坐标、金额等数据时很多人想当然地int(input())遇到带小数点的输入就崩。6.3 真值、可变默认参数与惰性求值易错点38if x判断的是真值不是是否为None或者是否为0。if 0: pass # False if 0.0: pass # False if : pass # False if []: pass # False if {}: pass # False if 0: pass # True字符串0非空False、0、0.0、空字符串、空列表、空字典、None在布尔上下文中全是False。很多人想判断列表是否为空用if len(arr) 0但直接if arr更Pythonic。反过来想判断变量是否为None写if x is None别写if not x——因为x 0或x 时not x也是True你就没法区分无值和值是0了。比赛里这个区分经常决定一个空数据用例的生死。易错点39可变默认参数是共享的def f(lst[])会累计状态。def add_item(item, lst[]): lst.append(item) return lst print(add_item(1)) # [1] print(add_item(2)) # [1, 2]不是 [2]默认参数在函数定义时只计算一次之后每次调用都复用同一个列表对象。这是Python经典的可变默认参数陷阱。正确写法是用None做哨兵def add_item(item, lstNone): if lst is None: lst [] lst.append(item) return lst易错点40map、filter、zip返回的是迭代器不是列表。m map(str, [1, 2, 3]) print(m) # map object at 0x... print(list(m)) # [1, 2, 3]要转列表才能看内容迭代器是惰性求值的只能遍历一次。很多人print(map(...))打印出一串看不懂的对象地址以为代码错了。更隐蔽的坑是迭代器遍历完一次就空了第二次list(m)得到空列表。比赛里要用map的结果做多次操作先lst list(map(...))转换成列表存下来。同理range也不是列表要列表就list(range(n))。7. 实战排查链路与时间优化一份可以照抄的自检清单7.1 一个WA案例的完整排查过程光讲知识点不如看一次真实的翻车全流程。我之前遇到一个学生写的词频统计题目标是统计单词出现次数按次数降序、字典序升序输出。他第一次提交的代码长这样words input().split() result [] for w in words: if w not in result: result.append([w, words.count(w)]) # count每次都是O(n) result.sort(keylambda x: (-x[1], x[0])) for w, c in result: print(w, c)本地样例输出全对。提交后第一个超大的测试点直接TLE。排查链路是这样的先看时间复杂度外层循环是O(n)里面words.count(w)又是O(n)合起来是O(n²)。如果单词量到10万这个循环的理论操作数是一百亿必超。这时候的修复思路不是去优化count的写法而是换数据结构——用Counter一次遍历统计完频率再排序。改成from collections import Counter words input().split() cnt Counter(words) items sorted(cnt.items(), keylambda x: (-x[1], x[0])) for w, c in items: print(w, c)同一份逻辑从O(n²)降到O(n log n)。这个案例的教训很典型不是算法不懂而是没意识到list.count这种感觉很方便的方法在循环里用就是O(n²)的隐形炸弹。另一个WA案例是浮点比较。题目要求判断两个点是否重合新手直接if x1 x2 and y1 y2结果因为浮点精度最后一位差了几个ulp全部判错。排查时先在本地打印x1 - x2发现是1e-16级别的误差立刻明白是精度问题。正确方案是abs(x1 - x2) 1e-9或者更稳的做法是读入时把所有坐标乘以一个缩放系数转成整数再比较。7.2 数据类型的复杂度估算备赛时我习惯让队员把常用操作的时间复杂度贴在手边出了TLE先查这组数据比瞎猜快得多。常见操作复杂度备注列表索引arr[i]O(1)列表末尾 append/popO(1)摊还列表中间插入/删除O(n)后续元素要移位x in 列表O(n)高成本操作x in 集合/字典O(1)平均情况字符串/列表切片O(k)拷贝k个元素.join(lst)O(n)总长度线性list.sort()O(n log n)Timsort实际很快Counter统计O(n)底层是哈希表dict.fromkeys去重O(n)保序去重的利器记住一句话凡是循环嵌套里出现遍历查找或反复拼接第一反应就是该换数据结构了。三重循环套in判断几乎必TLE不是你机器不够快是复杂度不允许。7.3 赛前自检清单每次正式比赛前十分钟我会把下面这份清单过一遍。它不能帮你写出满分算法但能挡住一大半低级WA和TLE涉及取模、整除的地方确认了负数方向吗用(x % n n) % n了吗有浮点数比较吗改成math.isclose或者缩放成整数了吗建二维数组用[[0] * n for _ in range(m)]不是[[0] * n] * m循环里用拼接字符串了吗改成join了吗删除列表元素用了倒序遍历或推导式过滤吗多条件排序的key返回元组了吗sort和sorted分清楚了吗大量判重用的是set/dict不是list的in吗map、filter的结果转成list了吗迭代器只用一次能意识到吗函数默认参数是可变对象吗换成None哨兵了吗读进来的数字字符串转int/float了吗int(1.2)这种报错能预判吗字典遍历时增删键了吗先收集list(d.keys())了吗输出多行数据时用\n.join(lines)了吗这份清单来源于我给参赛队员做赛前辅导时的总结我自己每次写比赛代码到最后也会对着它快速自查一遍。数据类型这种东西平时写业务代码时容错高错了大不了重跑一次但在比赛里每一个测试点都是一次性判定边界行为就是实打实的分数。把这40个点过完你再回头看那些明明逻辑对却WA的题会发现绝大多数都能对上号。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →