原题:
Given a constant K and a singly linked list L, you are supposed to reverse the links of every K elements on L. For example, given L being 1→2→3→4→5→6, if K = 3, then you must output 3→2→1→6→5→4; if K = 4, you must output 4→3→2→1→5→6.
Input Specification:
Each input file contains one test case. For each case, the first line contains the address of the first node, a positive N (<= 105) which is the total number of nodes, and a positive K (<=N) which is the length of the sublist to be reversed. The address of a node is a 5-digit nonnegative integer, and NULL is represented by -1.
Then N lines follow, each describes a node in the format:
Address Data Next
where Address is the position of the node, Data is an integer, and Next is the position of the next node.
Output Specification:
For each case, output the resulting ordered linked list. Each node occupies a line, and is printed in the same format as in the input.
Sample Input:
00100 6 4 00000 4 99999 00100 1 12309 68237 6 -1 33218 3 00000 99999 5 68237 12309 2 33218
Sample Output:
00000 4 33218 33218 3 12309 12309 2 00100 00100 1 99999 99999 5 68237 68237 6 -1
分析:
初看是一道很简单的题目,对链表进行有规律的反转。我采取的方案如下:
1.读取输入,然后链表按其地址存放到map中(当然有猥琐的人可以存放到数组里用空间换时间);
2.按照链表的头指针顺着下去读取链表。建一个栈,当没有达到K个时,每个读取到的值压入栈里,然后集齐K个的时候输出。技巧是一行输出的东西可以分拆分成两块,即除第一行与最后一行特殊外,其他每两行都是:
[上一地址 ] [上个值 ] [当前地址]
[当前地址] [当前值] [下一地址]
也就是说得到当前节点后,只需要补齐上一行的”当前地址”和当前行前两项即可,等到下一个节点读入时再补上这一行的最后一个“下一地址”。
3.最后,末尾别忘了NULL指针“-1”
上面的算法复杂度是O(N)
但是请务必考虑下面几个特殊情况:
1. K=1, K=N
2. 给的头指针不是整条链的头指针,而是中间某个节点的。这个问题是最后一个测试点测试的东西。我一开始也试了好多无果,还好搜到了这篇文章末尾的评论部分才得到启发!另外测试点6不会考虑给的测试例有多个next指针式NULL指针(-1)的情况,有些博客中这种说法是错误的。
例如:
00000 6 4 00000 4 99999 00100 1 12309 68237 6 -1 33218 3 00000 99999 5 68237 12309 2 33218
这时候的正确输出是:
00000 4 99999 99999 5 68237 68237 6 -1
代码
#include <iostream> #include <map> #include <stack> #include <string.h> using namespace std; struct Node { char fake_addr[6]; char fake_next[6]; int data; }; int main() { char pStart[6]; int N, K; cin >> pStart >> N >> K; map<int, Node> mapNodes; int multiEnd = 0; for (int i = 0; i < N; i++) { //Read from input char addr[6], next[6]; int data; cin >> addr >> data >> next; if (strcmp(next, "-1") == 0) multiEnd++; Node node; node.data = data; strcpy(node.fake_addr, addr); strcpy(node.fake_next, next); int key = atoi(addr); mapNodes[key] = node; } if (true) { //奇怪的的情况,需要扫链了 int count = 0; int nextPtr = atoi(pStart); while (nextPtr != -1) { nextPtr = atoi(mapNodes[nextPtr].fake_next); count++; } N = count; } stack<Node> workingStack; const int LIMIT = N - N % K; int currentFakePtr = atoi(pStart); bool firstLine = true; //能整除的范围 for (int i = 0; i < LIMIT; i++) { if (true) { //将node压入栈准备输出 if (currentFakePtr == -1) { break; } Node currentNode = mapNodes[currentFakePtr]; workingStack.push(currentNode); currentFakePtr = atoi(currentNode.fake_next); } if (i%K == K-1) { //逐条弹栈并输出 (除最后一个节点的next地址) while (!workingStack.empty()) { Node currentNode = workingStack.top(); if (!firstLine) cout << currentNode.fake_addr << endl; //上一行的末尾 cout << currentNode.fake_addr << " " << currentNode.data << " "; //本行的前两个元素 workingStack.pop(); firstLine = false; } } } //不能整除的范围,按顺序输出 //需要考虑一开始就不能整除的情况 (LIMIT = 0) for (int i = LIMIT; i < N; i++) { if (currentFakePtr == -1) { break; } Node currentNode = mapNodes[currentFakePtr]; if (!firstLine) cout << currentNode.fake_addr << endl; //上一行的末尾 cout << currentNode.fake_addr << " " << currentNode.data << " "; //本行的前两个元素 currentFakePtr = atoi(currentNode.fake_next); firstLine = false; } cout << "-1"; return 0; }
测试点
(这个结果还有优化的空间,不过既然已经<400ms了我就不管啦~)
测试点 | 结果 | 用时(ms) | 内存(kB) | 得分/满分 |
---|---|---|---|---|
0 | 答案正确 | 1 | 360 | 12/12 |
1 | 答案正确 | 1 | 232 | 3/3 |
2 | 答案正确 | 1 | 360 | 2/2 |
3 | 答案正确 | 1 | 232 | 2/2 |
4 | 答案正确 | 1 | 232 | 2/2 |
5 | 答案正确 | 326 | 8424 | 3/3 |
6 | 答案正确 | 1 | 360 | 1/1 |