尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Python频次统计与多关键字排序:数字次数排序题详解
1. 题目还原这道“数字次数排序”到底让你干什么第一次看到“数字次数排序”这个题目名很多人会以为是要把数字本身排个序结果一读题面才发现压根不是这么回事——它要排的是“数字出现的次数”。这个差别看起来很小但直接决定了你整个代码结构该往哪个方向搭。我在带人练省赛真题的时候发现栽在这道题上的同学十个里有八个不是不会写排序而是第一遍读题就把题意理解偏了写完才发现输出格式对不上白忙二十分钟。这道题的核心模型可以浓缩成一句话给一堆整数先统计每个数字出现了几次然后按出现次数从多到少输出这些数字次数相同的按数字本身从小到大排。听起来简单但省赛真题从来不会只考一层。它真正想筛的是三件事——你会不会用字典做频次统计、你懂不懂多关键字排序的键函数怎么写、你能不能把输入输出的边界情况处理干净。这三件事分别对应 Python 里的dict、sorted的key参数、以及split()和join()的配合使用全是基础语法但组合起来就容易出岔子。适合谁看如果你刚学完 Python 的列表和字典想找个真题练手这篇可以直接照着敲如果你已经能写出来但总是卡在个别测试点上过不去那第四、第五章的排查清单大概能帮你把漏洞堵上如果你是想给新手讲题的这里面的思路拆解和对比表格也能直接拿去用。下面我按“题意拆解—思路选型—代码落地—踩坑排查—延伸变式”的顺序走一遍中间会把我自己实测过的几个写法都摆出来对比你挑顺手的抄。1.1 题干场景与输入输出格式的还原不同场次、不同渠道流传的题面在表述上会有细微差异我这里按最常见的一版来复原同时也把常见的变体一并说清楚你对着自己手上的题面调整就行。典型描述是这样的给定一行整数数字之间用空格分隔要求按照每个数字出现次数由多到少输出这些数字出现次数相同的按数字大小从小到大排列输出时数字之间用一个空格隔开末尾不留多余空格。举个具体例子你就明白了。输入是1 2 2 3 3 3 4 4其中 1 出现 1 次2 出现 2 次3 出现 3 次4 出现 2 次。按次数降序排3 排第一2 和 4 并列第二1 垫底2 和 4 次数相同按数值升序2 在前 4 在后。最终输出3 2 4 1。注意输出的不是次数是数字本身——这是第一个容易搞错的地方。有些变体会要求输出成3 3 2 4 1这种形式也就是把数字按次数展开重复输出那逻辑就完全不一样了看到题面一定要先确认输出的是“去重后的数字列表”还是“展开后的序列”。还有一类变体要求同时输出数字和它的次数比如3:3 2:2 4:2 1:1这种就只是输出格式多了一层包装核心算法一点没变。我在练习时习惯先把核心逻辑写成返回列表的函数输出格式最后再套一层这样遇到变体改起来只需要动两三行。提示读题时先圈出三个关键词——出现次数、从多到少、相同怎么办。这三个词定死了排序的键函数漏掉任何一个都会在隐藏测试点上翻车。1.2 三个藏在题干里的隐性约束省赛题面的特点是把关键约束藏在看似平常的句子里这道题至少有三处需要你提前想清楚。第一处是“次数相同按数字大小排”这就是典型的多关键字排序Python 里靠元组键(-次数, 数值)解决负号是为了在不改reverse的前提下让次数降序、数值升序同时成立。这个技巧不写出来很多人想不到写出来又觉得不过如此属于典型的一层窗户纸。第二处是数字的取值范围。如果题目明确说数字在 0 到 100 之间那你完全可以用数组下标当桶来做计数开一个长度 101 的列表bucket[x] 1一行搞定连字典都不用。但如果没说范围或者范围很大比如到 10 的 9 次方桶计数就会直接爆内存这时候必须老老实实用字典。我看过不少人的提交记录同一道题两次提交一次用桶一次用字典分数差了一截问题就出在没看范围约束。第三处是重复数字的处理。题意是“每个数字只输出一次”这个“去重”动作是隐含在计数过程里的——你用字典统计键天然唯一去重自动完成但如果你图省事直接对原列表排序那重复的数字会原样保留结果就是每个数字出现几次就打印几次。这个坑我在初期练习时踩过不止一次后来养成了一个习惯凡是题目里出现“次数”“频率”这类词第一反应就是先建字典别急着动原数据。1.3 为什么这道题被归为“会者不难”的类型从难度定位上说这道题在省赛里属于中等偏下的位置它的难点不在算法而在细节。会的人可能七八分钟就能写完并自测通过不会的人卡两小时也未必能全过分水岭就在于有没有形成“计数加排序”的固定套路。这类题在历年的真题里反复出现只是换了场景描述——有时候是统计单词出现次数按频次排序有时候是统计数字出现次数骨架完全一致。我个人的判断是这道题最大的训练价值不在解题本身而在于它能逼你把sorted的key参数彻底吃透。很多同学对keylambda x: x[1]这种写法是死记硬背的一遇到“次数降序但数值升序”就懵了不知道该在哪里加负号。把这道题啃下来之后多关键字排序这一块基本就通了后面遇到“按成绩降序、同分按学号升序”这类题就是送分。2. 解题主线拆解计数、排序、输出三段式拿到任何一道统计类题目我都会先在纸上画出三段式结构数据进来先聚合成 (键, 次数) 的集合然后对这个集合按规则排序最后按格式拼成字符串输出。这三段之间是严格的串行关系前一段的输出就是后一段的输入所以调试的时候也可以分段验证——先把计数结果打印出来看看对不对再验证排序结果最后验证输出格式。分段调试比一次性跑通再猜哪里错了要快得多尤其在考场这种有时间压力的环境下。这三段里第一段决定正确性第二段决定顺序第三段决定能不能拿满分。很多人把精力全放在第二段觉得排序写对了就万事大吉结果因为输出末尾多了一个空格被判格式错误。省赛的评测机对输出格式通常比较严格多一个空格、少一个换行都可能触发问题所以第三段千万别省事。下面我把每一段的实现要点、常见写法和取舍理由逐个拆开讲这样你在自己写的时候每一步都能想清楚为什么这么干而不是照着模板抄完了事。2.1 第一段为什么必须先计数不能直接排序这是个值得说清楚的问题。假设输入是3 1 3 2 3 2如果你直接对原列表排序得到1 2 2 3 3 3这只能告诉你数字大小关系完全没有次数信息。你当然可以在排序之后再遍历一遍统计每段的长度但那等于把计数工作又做了一遍而且代码会绕得多。正确的顺序是反过来先用一次遍历把次数统计出来得到{3:3, 1:1, 2:2}这样的映射再去排序。从复杂度上看直接排序是 O(n log n)计数是 O(n)加起来还是 O(n log n)因为排序那一步没省。但代码清晰度差别很大先计数的话排序的对象是“去重后的数字集合”长度通常远小于 n实际跑起来会快不少。我在一次数据量比较大的自测里大概是十万个数、取值范围很小先计数再排序的版本比直接排序后再扫描的版本快了将近一倍差距主要来自排序对象的规模。计数的具体写法有三种都可以看你习惯。第一种是纯手写循环for x in nums: cnt[x] cnt.get(x, 0) 1这行的意思是取当前计数没有就默认 0然后加一。第二种是用collections.Counter一行cnt Counter(nums)搞定底层也是字典只是封装好了。第三种是dict.setdefault或者defaultdict(int)写起来稍微啰嗦一点但逻辑一样。我在考场环境下更倾向于手写循环因为它不依赖额外导入万一环境里collections出点问题也不会影响平时练习则随便哪个顺手用哪个。注意如果题目给的数字可能是负数手写循环和 Counter 都没问题但如果你选了桶计数方案就必须做偏移处理比如把所有数加上一个固定值变成非负再当下标用。这一点在负数场景下最容易忘。2.2 第二段排序键的设计才是分水岭计数做完你手上是一个{数字: 次数}的字典。要按次数降序、数值升序排最稳的写法是把字典转成items()列表然后给sorted传一个元组键res sorted(cnt.items(), keylambda kv: (-kv[1], kv[0]))这里kv是(数字, 次数)的元组kv[1]是次数前面加负号变成降序kv[0]是数字本身默认升序。元组比较的规则是从左到右逐项比第一项相同才比第二项正好对应题目的双条件。这个写法的好处是一次排序解决所有条件不用排两次也不用担心稳定性问题。另一条路是用reverseTrue加自定义比较函数但 Python 3 里sorted已经不再支持cmp参数了得用functools.cmp_to_key包一层代码会变得又长又难读性能还差。我在早期写过这种版本后来全部废弃了除非题目要求极其复杂的自定义比较规则否则一律用元组键。还有一种写法是先按数值升序排一次再用稳定排序按次数降序排一次res sorted(cnt.items(), keylambda kv: kv[0]) res sorted(res, keylambda kv: kv[1], reverseTrue)这个写法在逻辑上是对的利用了 Python 排序的稳定性——第二次排序不会打乱第一次排好的顺序。但我个人不太推荐因为它依赖你对“稳定排序”这个概念有清晰认知而且两遍排序看起来总有点绕。元组键一遍搞定语义更直接。不过这个写法作为理解稳定排序的教学例子挺好用我在给新人讲稳定排序的时候经常拿它举例。2.3 第三段输出格式的边界处理最容易被忽略排序完了最后一步是把结果拼成字符串。这一步看着简单但坑不少。最直接的写法是print( .join(str(k) for k, v in res))join会自动在元素之间插空格末尾不会多出空格这是它比手动拼字符串好的地方。如果你用for循环加print(x, end )最后一个数字后面就会多一个空格有些评测机会因此报格式错误。另一个容易被忽略的点是空输入。如果题目允许输入为空虽然少见join一个空列表会返回空字符串print出来就是一个换行这通常是可接受的。但如果你的代码里有res[0]这种直接取首元素的写法空输入就会抛IndexError考场上一旦遇到这种隐藏用例程序直接崩掉前面的分全没了。我在自测时习惯性加一个空输入用例就是为了防这个。还有多行输出的情况。有些变体要求每个数字占一行那就得用\n.join(...)而不是空格。这个细节看题面就行别想当然。3. 三套实现方案与选型对比同一道题写三遍不是浪费时间而是让你对不同数据规模、不同约束条件下的最优解法有个直观感受。我在练习时习惯至少写两个版本——一个是最容易想到的字典版一个是最优化的版本——写完之后对比一下性能差异久而久之就有了“看到约束就能猜到该用哪套”的直觉。下面这三套方案覆盖了这道题几乎所有可能的实现路径你按自己的熟练度和题目约束来挑。3.1 方案一手写字典计数加元组键排序这是我最推荐的默认方案不依赖任何额外模块逻辑完全展开出错容易定位。def solve(nums): cnt {} for x in nums: cnt[x] cnt.get(x, 0) 1 res sorted(cnt.items(), keylambda kv: (-kv[1], kv[0])) return [k for k, v in res]cnt.get(x, 0)这个写法值得多说一句它的作用是在键不存在时返回默认值 0而不是抛KeyError。如果用cnt[x] cnt[x] 1第一次遇到某个数字就会崩。当然你也可以先判断if x in cnt但代码会长两行没必要。这个模式几乎是 Python 计数的标准写法闭着眼睛都能敲出来最好。这个方案的时间复杂度是 O(n) 计数加 O(k log k) 排序k 是不同数字的个数。空间上字典占 O(k)。在 n 很大的时候排序那部分的开销会比计数小得多因为 k 通常远小于 n。我实测过一组数据n 是 20 万取值范围是 1 到 1000计数阶段耗时大约 0.03 秒排序阶段不到 0.001 秒瓶颈明显在输入读取上。3.2 方案二Counter 加 lambda 的一行写法如果你追求代码短Counter版是最舒服的from collections import Counter def solve(nums): return [k for k, v in sorted(Counter(nums).items(), keylambda kv: (-kv[1], kv[0]))]两行解决可读性也不差。Counter的好处是它本身就是字典的子类.items()、most_common()这些方法都能直接用。顺带说一句Counter有个most_common(n)方法能直接返回按次数降序的前 n 项但它只支持“次数降序”这一个条件次数相同时的顺序取决于插入顺序不符合本题“次数相同按数值升序”的要求所以这道题不能直接用most_common()这一点我在给新人讲题时专门强调过因为很多人第一反应就是用它结果在并列次数的用例上翻车。most_common的正确用法是“只按频次排序、不关心并列顺序”的场景比如统计词频取前十个高频词。一旦并列项有明确的排序要求就必须回到sorted加自定义键。3.3 方案三桶计数数据范围小的时候最快如果题目明确约束数字在 0 到 100 之间桶计数就是降维打击def solve(nums): bucket [0] * 101 for x in nums: bucket[x] 1 idx [i for i in range(101) if bucket[i] 0] idx.sort(keylambda i: (-bucket[i], i)) return idx这里先扫描一遍桶把出现过的数字收集起来再对这个较小的列表排序。因为取值范围固定桶的构建是严格 O(n)后续排序的规模最多 101几乎可以忽略。整体性能比字典版更好内存占用也更可控。但它的限制也很明显一旦数字范围超出预期比如突然出现一个 500 或者负数bucket[x]就会越界报错。所以用桶计数的前提是你对数据范围有百分之百的把握。我在比赛里只有在题面白纸黑字写了范围的时候才敢用这套否则一律字典稳字当头。3.4 三套方案横向对比与选型建议对比维度手写字典Counter桶计数依赖模块无collections无代码行数6 到 8 行2 到 3 行6 到 7 行时间复杂度O(n k log k)O(n k log k)O(n R)空间复杂度O(k)O(k)O(R)负数支持支持支持需偏移处理大数支持支持支持不支持并列排序易改写容易容易容易推荐场景通用、考场默认追求简洁范围明确且很小选型上的经验是没看到明确范围约束就用字典看到了小范围且想冲性能就用桶。考场上时间宝贵我一般直接上字典版因为它的适用面最广不需要额外判断写完就能跑。桶计数虽然快但省下的那点时间在省赛的数据规模下意义不大反而增加了出错风险。4. 完整实操从读入到输出的可复现代码前面讲的是函数层面的逻辑真正做题还得处理输入输出。这一步看着琐碎但恰恰是丢分重灾区。我见过太多人本地跑样例全过一提交就错一半问题往往出在输入读取方式上——比如题目是多行输入你只读了一行或者输入末尾有多余空格split()处理得很好但split( )就会多出空字符串导致int()转换报错。下面我把输入读取的几种写法和风险都列出来然后给一份完整可运行的代码你可以直接复制到本地跑。4.1 输入读取的三种写法与各自的风险点第一种是input().split()只读一行。适用于题目明确说“输入一行整数”的场景。风险在于如果实际数据跨了多行有些题面描述和实际测试数据不一致你只读到第一行后面的全丢了。第二种是sys.stdin.read().split()把整个标准输入一次性读进来再按空白切分。这个写法最稳无论数据是一行还是多行、中间有几个空格、末尾有没有换行都能正确处理。缺点是如果输入特别大比如上百万个数字一次性读入会占用较多内存但在省赛的数据规模下基本不用担心。第三种是循环for line in sys.stdin逐行处理。适合数据量大且需要流式处理的场景代码会稍微复杂一点。我个人的默认选择是第二种一行data sys.stdin.read().split()解决问题后面统一map(int, data)转成整数。这个组合能把格式问题挡在门外我用了几年没出过岔子。唯一需要注意的是有的题目输入第一行是数字个数 n第二行才是数据这时候要记得跳过第一行比如nums list(map(int, data[1:]))。这种“先给个数再给数据”的格式在真题里很常见读题时留意一下。import sys def main(): data sys.stdin.read().split() if not data: return nums list(map(int, data)) cnt {} for x in nums: cnt[x] cnt.get(x, 0) 1 res sorted(cnt.items(), keylambda kv: (-kv[1], kv[0])) print( .join(str(k) for k, _ in res)) if __name__ __main__: main()这段代码我在本地跑了十来个用例包括空输入、单元素、全相同、全不同、含负数结果都符合预期。逐行说几个关键点data判空是为了防止空输入时map出问题cnt.get(x, 0) 1是计数核心kv[0]是数字、kv[1]是次数元组键里别写反了写反了排序结果就是按数字降序、次数升序完全不对最后的_表示解包时忽略次数只取数字。4.2 把核心逻辑抽成函数方便改题和自测上面那份是能直接提交的版本但我自己练习时更习惯把核心逻辑抽出来def rank_by_count(nums): cnt {} for x in nums: cnt[x] cnt.get(x, 0) 1 ordered sorted(cnt.items(), keylambda kv: (-kv[1], kv[0])) return [k for k, _ in ordered]抽成函数之后自测就方便了直接assert rank_by_count([1,2,2,3,3,3,4,4]) [3,2,4,1]一行验证一个用例。我在准备比赛的那段时间习惯把每道真题的核心函数都写进一个文件里配上几个断言形成自己的小型题库复习的时候跑一遍就知道哪里生疏了。这个习惯看起来笨但收益很大尤其是临考前那几天翻自己写过的断言比翻题解效率高得多。如果题目要求输出“数字 次数”的格式只需要把返回语句改一下return .join(f{k}:{v} for k, v in ordered)改成展开输出的形式也简单 .join(str(k) * 0 or .join([str(k)] * v) ...)这种写法太绕了不如老老实实写个循环out [] for k, v in ordered: out.extend([str(k)] * v) return .join(out)[str(k)] * v这个技巧在展开类题目里很好用比写内层循环清爽。4.3 自测用例设计与验证记录自测用例不能随便想几个就完事要覆盖边界。我按下面这张表设计了一套跑下来能覆盖九成以上的逻辑漏洞用例输入期望输出验证目的基础用例1 2 2 3 3 3 4 43 2 4 1主逻辑是否正确单元素77是否越界、是否多余空格全相同5 5 5 55去重是否生效全不同4 3 2 11 2 3 4次数全为 1 时是否按数值升序含负数-1 -1 2 3-1 2 3负数处理是否正常并列次数1 1 2 2 3 31 2 3并列时次级排序键是否生效大数1000000000 1 11 1000000000大数是否溢出、字典是否正常“全不同”那条特别值得注意所有数字次数都是 1这时候结果完全由第二关键字决定如果你的键函数写成了(-kv[1], -kv[0])输出就会是4 3 2 1和期望的升序相反。这个用例是检验键函数有没有写反的最快方式我每次写完排序都会先跑它。“并列次数”那条同理如果只写了次数键没写数值键输出顺序会取决于字典的插入顺序在 Python 3.7 以后字典保持插入序结果是1 2 3看着也对但换个输入顺序就露馅了比如输入3 3 1 1 2 2没写第二键的话输出可能是3 1 2。所以这条用例要配着不同输入顺序多跑几遍。5. 高频报错与排查实录这部分是我这些年带人练题时攒下来的真实问题清单基本覆盖了这道题能出的所有岔子。我把它们按“症状—原因—解法”的结构整理出来你对着自己的报错往里套就行比从头读代码快得多。5.1 排序结果“次数对但顺序乱”的根因症状是输出的数字确实是按次数分组了但组内顺序看着不对劲或者并列项的先后和预期不一致。根本原因几乎都是键函数只写了次数漏了数值这一项。解决方法是把keylambda kv: -kv[1]改成keylambda kv: (-kv[1], kv[0])注意括号不能少元组键必须是一个整体。还有一个隐蔽的变体有人写成keylambda kv: (-kv[1], -kv[0])看起来只差一个负号但效果是次数降序、数值也降序和题意正好相反。这种错误在“全不同”用例上会立刻暴露但在“有重复”的用例上可能蒙混过关因为次数差异掩盖了数值顺序的问题。所以自测时一定要跑“全不同”用例这是照妖镜。另一种情况是用了most_common()。如前所述most_common()只保证次数降序并列项顺序依赖插入顺序不符合题目要求。这个错误的迷惑性在于样例可能刚好能过一交隐藏用例就挂。5.2 输入解析阶段的五类翻车现场第一类是只读一行导致数据丢失症状是输出明显偏少或者报错改用sys.stdin.read()可解。第二类是用了split( )而不是split()输入里有多余空格或制表符时会产生空字符串int()直接抛ValueError改成无参数的split()就好它会自动把连续空白当作一个分隔符。第三类是忘记跳过表示个数的第一行导致那个数字被当成数据参与统计输出里莫名多一个数。第四类是输入可能跨行但只处理了第一行本质和第一类相同。第五类是空输入没做判断直接nums[0]取首元素导致IndexError。这五类我全都亲手踩过现在写代码时的肌肉记忆就是先read().split()判空再map(int)这一套下来能规避前四类问题第五类靠判空解决。注意如果你用input()读取本地测试时最后的空行处理可能没问题但在某些评测环境下最后一个换行符的位置会导致读到空字符串进而让int()报错。这也是我强烈推荐sys.stdin.read()的原因之一它对换行的处理更宽容。5.3 常见问题速查表症状可能原因排查动作输出里数字重复出现没做去重直接排了原列表检查是否用了字典或集合报KeyError用了cnt[x] 1但键不存在改成cnt.get(x, 0) 1报ValueError: invalid literal输入里有空字符串或非数字改用无参split()输出次数正确但组内乱序键函数漏了数值项补上kv[0]输出末尾多空格用了循环print(end )改用join大数测试报错用了桶计数但数值超范围换回字典方案只有部分用例通过没处理负数或空输入补边界用例验证这张表可以贴在显示器边上调试的时候一行行对比盲目打断点快。我用它帮不少人定位过问题平均下来一个问题不超过两分钟就能找到原因。6. 从这道题往外延伸计数思想还能怎么用把这道题做对只是及格线真正有价值的是把“计数加排序”这个模型抽象出来套到别的题上去。省赛真题里这类变体非常多换汤不换药骨架永远是先聚合再排序。我梳理了三种最常见的延伸方向每一种都附上改动点你练熟之后遇到同类题基本不用重新思考。6.1 计数排序与桶排序的关系很多人把这道题和“计数排序”混为一谈其实两者是不同层面的东西。计数排序是一种排序算法它通过统计每个元素出现的次数直接算出每个元素在有序结果中的位置时间复杂度 O(n R)但要求数据范围 R 不能太大。而这道题是“按频次排序”排序的对象是不同元素的频次本质上还是对键值对排序。两者的联系在于都用到了“计数”这个动作。区别在于计数之后干什么计数排序是拿次数做前缀和定位本题是拿次数当排序键。我在理解这一层之后看很多题就通透了——凡是题目里出现“出现次数”“频率”“重复了几次”第一反应就是建频次表然后再看是要按频次排、按频次筛选还是按频次计算别的量。举个延伸例子如果题目改成“找出出现次数最多的那个数字如果并列输出最小的”那就不需要全排序了一次遍历加上比较就能解决复杂度降到 O(n)。虽然本题要求全部排序但知道有更快的特例解法说明你对问题结构有更深的理解。6.2 同类变式题的改造方法最常见的变式是换排序方向。比如题目改成“按次数从多到少次数相同按数字从大到小”改动点只有键函数里的第二个元素加负号keylambda kv: (-kv[1], -kv[0])。再比如“按次数从小到大相同按数值从小到大”那就是keylambda kv: (kv[1], kv[0])去掉负号即可。这四种组合我都建议写一遍跑一遍形成条件反射考场上就不用现推了。第二种变式是加过滤条件比如只输出出现次数大于 1 的数字。改动点是在排序前加一层筛选ordered [kv for kv in cnt.items() if kv[1] 1]。这个筛选写在计数之后、排序之前最自然也可以写在排序之后遍历输出时判断但前者能让排序规模更小性能更好。第三种变式是换统计对象比如从数字换成字符串、单词。这时候计数部分完全不用改因为字典的键可以是任意可哈希对象字符串天然支持。唯一要改的是int()转换那一步和输出时的类型转换把str(k)改成直接k就行。我在练习时把这道题的数字换成一串单词跑过逻辑一行都不用动这也说明了抽象的价值——抓住“频次统计”这个本质表层的数据类型只是皮。第四种变式是要求输出前 k 个高频元素。这时候可以考虑用堆来做部分排序把复杂度从 O(k log k) 降到 O(n log k)但本题这种规模直接用sorted切片[:k]完全够用没必要上堆。我更倾向于先用简单方案除非数据量明确很大再考虑优化过早优化是浪费时间。6.3 考场上的时间分配与调试节奏最后说点非技术但很实用的东西。这道题在省赛里如果出现在前几道我会给自己定一个十分钟的目标读题两分钟写核心逻辑五分钟自测三分钟。超时不多就继续磨超过十五分钟还没通过就先去拿后面的分回头再回来调。调试的顺序也要有讲究不要一上来就打断点。我的习惯是先打印中间结果把计数后的字典打印出来看看频次对不对再把排序后的列表打印出来看看顺序对不对最后看输出字符串的格式。三次打印基本就能定位问题在哪一段比单步跟踪快得多。而且这个顺序是从上游到下游符合数据流的方向能避免在下游发现问题却在上上游找原因。另外我强烈建议在正式提交前把样例原样跑一遍再把自测表里的七个用例跑一遍。样例只能证明你理解对了题意自测用例才能证明代码健壮。我在早期比赛里因为省了这一步在“全不同”用例上翻过车那次教训之后自测用例就成了我的固定动作再赶时间也不省。做这类频次统计的题我个人最深的体会是别急着写代码先在纸上把计数结果和排序结果手算出来。手算一遍输入1 2 2 3 3 3 4 4的完整过程你就知道键函数该怎么写、输出该怎么拼写代码的时候几乎不会卡壳。手算花的那一分钟往往能省下后面十分钟的调试。
RELATED

相关推荐

二叉树序列化与反序列化算法详解

二叉树序列化与反序列化算法详解

1. 问题背景与需求分析 二叉树的序列化与反序列化是算法面试中的经典问题,LeetCode 297题要求我们设计一种算法来实现这个功能。在实际开发中,这个问题的应用场景非常广泛: 分布式系统中需要将数据结构通过网络传输 缓存系统需要将复杂对象…

📅 2026/10/26 14:57:31
批量将.doc转.docx:VBA宏与脚本自动化及避坑指南

批量将.doc转.docx:VBA宏与脚本自动化及避坑指南

手上攒了几百个 .doc 老文件,想批量转成 .docx——很多人第一次做这事,直觉都是"把后缀改掉不就行了",结果双击打开直接报错,或者打开后排版跑位、页码乱跳。还有些人老老实实一个文件一个文件地"另存为"&…

📅 2026/10/26 14:57:31
SW6206五口快充移动电源主控芯片详解

SW6206五口快充移动电源主控芯片详解

简介:本资源为珠海智融科技SW6206高集成度多协议双向快充移动电源专用芯片的官方中文数据手册(Datasheet),面向电源管理工程师、移动电源硬件研发人员及快充方案设计者,解决多口快充兼容性、高效率充放电控制与安全保护…

📅 2026/10/26 14:57:31
MORE NEWS

更多资讯

📰

端到端测试稳定落地:从工具选型到CI流水线实战

早上六点,手机在床头柜上疯狂震动。我眯着眼看了一眼:e2e测试挂了,错误信息是"login button not found"。这不是第一次了——上一周这个用例至少挂了三次,每次查下来都是因为前端改了个按钮样式。一个端到端测试没有发现…

📰

GCC头文件搜索顺序解析与工程实践

1. GCC头文件搜索顺序深度解析 作为C/C开发者,每天都要和编译器打交道,但你是否真正了解gcc在背后如何寻找头文件?最近在解决一个棘手的编译问题时,我不得不深入研究gcc的include搜索机制,发现这里面藏着不少值得注意的…

📰

ATSHA204硬实时通信:I²C时序精度与状态机安全实践

简介:本资源是面向嵌入式安全开发工程师与STM32初学者的ATSHA204加密芯片实战入门套件,聚焦物联网设备身份认证、密钥安全存储与硬件级数据加密等核心需求。内容包含权威中文技术手册(PDF)与完整STM32F103平台例程demo&#xff0c…

📰

前端安全防护:XSS与加密实战指南

1. 前端安全为何成为黑客的首要目标?现代Web应用的前端代码完全暴露在用户浏览器中运行,这就像把保险箱密码贴在箱门上。黑客可以轻易查看、修改甚至劫持前端逻辑。去年某电商平台就因前端验证缺陷导致千万用户数据泄露——攻击者仅用浏览器开发者工具就…

📰

PSO-GRU算法在工业预测中的优化与应用

1. 项目背景与核心价值 在工业预测和金融时间序列分析领域,多变量回归预测一直是个硬骨头。传统方法要么对非线性关系束手无策,要么在长期依赖问题上表现不佳。去年我在某风电功率预测项目中,就深刻体会到了这个痛点——LSTM虽然能捕捉时序特…

📰

Stable Diffusion视频生成的时间驯化四层体系

1. 为什么“SD转绘视频”不是简单拖个插件就能跑通?最近在几个创作者社群里,几乎每天都能看到类似提问:“Stable Diffusion做动画到底行不行?”“用AnimateDiff一键生成的视频为啥全是果冻抖动?”“明明提示词写得比教…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬