PTA链表重排题保姆级攻略从空间换时间到双指针优化我的踩坑实录第一次在PTA上遇到这道链表重排题时我花了整整三个小时才勉强通过所有测试点。当时采用的是一种典型的空间换时间策略——用大数组存储所有节点信息。虽然最终AC了但代码冗长且效率不高。后来经过反复优化终于找到更优雅的双指针解法。本文将分享这段从暴力解法到优化方案的完整思考过程。1. 问题重述与初步分析题目要求将单链表L1→L2→...→Ln重新排列为Ln→L1→Ln-1→L2→...的形式。例如输入链表1→2→3→4→5→6输出链表6→1→5→2→4→3关键难点在于PTA的输入格式特殊节点地址为5位非负整数NULL用-1表示数据规模可能很大N≤10^5需要考虑时间复杂度需要保持原有节点的数据关系不变我最初的做法是定义一个超大数组来存储所有节点信息#define MAX 100001 typedef struct { int data[MAX]; int next[MAX]; } HashTable;这种方法的优势是通过数组下标直接访问节点O(1)时间查询实现思路直观适合初次接触这类题目但存在明显缺陷空间浪费严重实际可能只用到很小一部分当N很大时多重循环可能导致超时代码可读性差维护困难2. 空间换时间方案的实现与局限2.1 基础实现步骤我的第一版解决方案主要分为三个阶段数据读取阶段使用HashTable结构存储所有节点记录头节点地址和总节点数链表重建阶段遍历原始链表将节点指针存入数组按照新顺序重新连接节点结果输出阶段处理地址格式补前导零按新链表顺序输出核心代码如下void reorderList(HashTable* ht, int head) { int nodes[MAX], count 0; // 将链表节点地址存入数组 for (int p head; p ! -1; p ht-next[p]) { nodes[count] p; } // 重新连接节点 int left 0, right count - 1; while (left right) { ht-next[nodes[right]] nodes[left]; right--; if (left right) { ht-next[nodes[left]] nodes[right]; left; } } ht-next[nodes[left]] -1; }2.2 遇到的典型问题在实际提交时我遇到了几个典型的PTA判题问题边界条件处理不足未考虑空链表情况对单个节点链表的处理出错格式输出问题地址补零处理不完整最后一个节点的next地址应为-1但误输出为NULL效率问题当N10^5时双重循环导致超时大数组初始化耗时解决方案增加边界条件检查统一使用格式化输出函数优化循环结构减少不必要的操作3. 双指针优化方案经过多次尝试我发现可以使用双指针技术在不使用大数组的情况下解决问题。这种方法的核心思想是找到链表的中点反转后半部分链表合并两个链表3.1 具体实现步骤步骤一快慢指针找中点ListNode* findMiddle(ListNode* head) { ListNode *slow head, *fast head; while (fast-next fast-next-next) { slow slow-next; fast fast-next-next; } return slow; }步骤二反转后半部分链表ListNode* reverseList(ListNode* head) { ListNode *prev NULL, *curr head; while (curr) { ListNode *nextTemp curr-next; curr-next prev; prev curr; curr nextTemp; } return prev; }步骤三合并两个链表void mergeLists(ListNode* l1, ListNode* l2) { while (l1 l2) { ListNode* l1_next l1-next; ListNode* l2_next l2-next; l1-next l2; l2-next l1_next; l1 l1_next; l2 l2_next; } }3.2 复杂度分析方法时间复杂度空间复杂度适用场景数组存储法O(N)O(N)简单场景N较小时双指针法O(N)O(1)大规模数据要求空间效率双指针方案的优势不需要额外存储空间只需遍历链表几次效率更高代码更简洁易于理解和维护4. PTA提交注意事项在PTA平台提交这类题目时有几个关键点需要注意输入输出格式地址必须保持5位不足补前导零NULL必须输出为-1最后一个节点的next地址必须为-1特殊测试用例空链表情况单节点链表最大规模数据测试N10^5性能优化技巧避免使用cin/cout改用scanf/printf减少不必要的变量和操作使用更高效的算法如双指针法常见错误处理// 正确输出格式示例 void printAddress(int addr) { if (addr -1) printf(-1); else printf(%05d, addr); } // 节点输出函数 void printNode(int addr, int data, int next) { printAddress(addr); printf( %d , data); printAddress(next); printf(\n); }5. 从这道题中学到的编程思维这道链表重排题让我深刻理解了几个重要的编程概念时间与空间的权衡初版方案用空间换时间简单但不够优雅优化方案通过算法改进同时保证了时间和空间效率指针操作的技巧快慢指针找中点链表反转的多种实现方式链表合并的边界条件处理PTA题目的特点注重边界条件和格式要求大数据量测试点考察算法效率需要兼顾正确性和性能在实际编码过程中我建议可以先写出基础方案确保正确性再逐步优化算法效率最后处理格式和边界条件这种分阶段的开发方式可以帮助我们更系统地解决问题而不是一次性处理所有复杂情况。