OJ提交TOP K问题代码遇Runtime Error,本地测试正常求排查
兄弟,我太懂你这种本地测样例全过、OJ一提交就Runtime Error的憋屈了!这种情况基本都是代码在边界测试用例下触发了非法操作,毕竟OJ的测试集可比你本地的样例复杂多了。结合你用大顶堆+K次删除的思路,我给你梳理几个最可能踩的坑:
数组越界访问
看你代码开头用了long类型的数组,如果是手动实现堆的话,有没有考虑堆数组的大小?比如OJ给的输入数组长度远大于你初始化的堆数组容量,插入元素时直接越界写内存——本地小测试用例没问题,但大case直接崩。另外,堆调整的siftDown/siftUp函数里,访问子节点(比如heap[i*2+1])前,有没有先判断索引是否小于当前堆的元素个数?漏了这个判断的话,很容易访问到数组外的非法内存。堆初始化逻辑错误
手动构建大顶堆时,必须从最后一个非叶子节点开始向上调整堆结构。如果你的初始化逻辑错了(比如从根节点开始调整),堆的结构根本不合法,后续删除操作时可能会访问到异常位置。另外,有没有处理数组长度小于K的情况?如果输入数组的元素总数比K小,你硬要执行K次删除操作,相当于去删空堆,必然触发错误。输入处理不严谨
OJ的输入可能和你本地测试的格式差异很大:比如输入元素个数极多,你用cin读取时没关闭同步(可以加ios::sync_with_stdio(false); cin.tie(0);加速),导致读取超时?或者你假设输入有固定N个元素,但实际OJ给的输入更多/更少,导致数组越界。另外,有没有可能输入包含负数?虽然大顶堆逻辑不影响,但如果你的堆比较逻辑写反了(比如把大顶堆写成小顶堆),会不会在极端情况下触发内存异常?动态内存分配问题
如果堆数组是用new long[]动态分配的,有没有确保分配的大小足够?比如你按本地样例的大小分配,OJ测试用例更大就会越界。另外,如果是静态数组,大小设得太小,同样会触发越界错误。
快速排查建议
- 优先改用STL的
priority_queue实现大顶堆,它会自动处理内存和边界,减少手动实现的出错概率;- 在所有堆操作的索引访问前,强制加边界判断(比如
if (left < heapSize));- 提前处理边界case:比如K为0、数组长度小于K时,直接输出整个数组升序;
- 用
while(cin >> num)的方式读取所有输入元素,不要假设固定的输入个数。
内容的提问来源于stack exchange,提问作者Liam_1998

