首页 > 代码库 > 【Zhejiang University PATest】02-1. Reversing Linked List

【Zhejiang University PATest】02-1. Reversing Linked List

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 400000 4 9999900100 1 1230968237 6 -133218 3 0000099999 5 6823712309 2 33218
Sample Output:
00000 4 3321833218 3 1230912309 2 0010000100 1 9999999999 5 6823768237 6 -1

【solution】
初看题意,很简明易懂。(不要被表象迷惑了。。
链表嘛,还手动给出了节点地址,于是开始写。
等我经历了一番折腾之后,我觉得这道题堪称打表审题,因为它实在是把这个点用表象隐藏得很好。想明白了之后实现就并不难了。

说下我的“心路历程”:
很快发现这题的关键在于“段与段”之间的“地址”连接处要处理好。
一开始,特意用结构体来构造出节点,三个成员,data, addr(自己的地址),next(下一个节点地址),其中地址用字符串来存储,然后创造一个元素是结构体的数组(得强调一下物理地址是相邻的一块内存)。
很自然的,我开始用输入数据构造一个串。怎么构造呢?地址都是字符串,又很自然的,随手开始暴力查找下一个节点,显然是个O(n^2)的。然后想,我擦,不会过不了吧。有优化吗?一时并没有想到(与字符串存地址的先入思维有关)。
然后想,唉这才第二周第一道题,测试数据应该不会很坑吧。(事实上我已经掉坑里了 T_T)

然后写完一测试,一个点超时,一个点竟然还WA了!超时还可以理解,竟然还有WA!
然后首先开始解决WA的问题(因为超时可能也是程序对某些测例出错引起的)。再看代码,边界情况应该都没有问题啊。
在讨论区受陈越姥姥提醒,输入数据中的节点竟然有可能不在有效的需要输出的链上!也就是最后输出的链长可能没有 n !因为输入里面有无效节点!T_T
姥姥(出题人)真是心思缜密啊![苦笑]

然后WA解决了,可是还是有超时。
看来问题是出在 O(n^2) 的构造链上。
再看代码,觉得可能是地址复制来复制去的字符串操作影响了效率,这才终于开始思考把地址用整型来存储。
马上把地址改成了整型,还是超时。
问姥姥,姥姥说是有点小技巧,复杂度是 O(n) 的。
竟然是 O(n) 的!!我才开始认真思考起优化来。
是不是要排序啊?给地址排个序然后二分查找?即便如此也是 O(nlogn) 啊。而且第二周诶,还没讲诶,不会这么复杂吧。[再次苦笑]
开始还一直桎梏于地址为字符串的思路里,甚至想到了 哈希表、优先级队列、完全二叉堆 等等数据结构。可是这才第二周啊![大声苦笑加自嘲]
大概是习惯了打表对于大多数题肯定不会是标准解法,其原因在于题目数据范围一般较大,慢慢的忘了“初心”了。[骗分导论加苦笑!]
这道题真的隐藏得很好,姥姥真是有心了。

思维经历一番千回百转的浪潮,终于想到了将地址作为数组的数值下标,而数组值是数据内容以及下一个节点地址这种被我称作“打表”的办法。
不禁一阵唏嘘啊 T_T

有几点要说:
1、不要小看任何一道题;
2、这道题真正巧妙的揭示了列表和向量的区别与本质,看似题目是列表,实际做起来却是向量;
3、代码中,输出前导0的格式控制:%05d。向右对齐,最少占5位,不足用0填补。

AC代码如下,可能空间上还可以优化,由于我为了竟可能少改动原始版的代码就做不做大幅改动了:
 1 #include <stdio.h>  2 #include <malloc.h> 3  4 #define AddrMAX 1000004 5  6 typedef struct AnsNode 7 { 8     int addr, data; 9 }anode, *panode;10 11 int main(void)12 {13     int n, k, i, j, block, rest, top = 0;14     int start, temp;15     16     scanf("%d %d %d", &start, &n, &k);17     18     int* data = http://www.mamicode.com/(int *)malloc(sizeof(int)*(AddrMAX));19     int* next = (int *)malloc(sizeof(int)*(AddrMAX));20     21     panode ans = (panode)malloc(sizeof(anode)*(n+1));22     23     for (i = 0; i < n; i++)24     {25         scanf("%d", &temp);26         scanf("%d %d", &data[temp], &next[temp]);27     }28     29     // 按地址将链构造好放入ans中 30     while (start != -1)31     {32         ans[top].data =http://www.mamicode.com/ data[start];33         ans[top].addr = start;34         start = next[start];35         top++;36     }37     n = top;38     39     // 每 K 段输出一次,并且处理最后一次不足k个的情况,关键点在于“段与段”之间“地址 ”的拼接 40     block = n / k; rest = n % k;41     for (j = 0; j < block; j++)42     {43         for (i = (j + 1)*k - 1; i > j*k; i--)44         {45             printf("%05d %d %05d\n", ans[i].addr, ans[i].data, ans[i-1].addr);46         }47         printf("%05d %d ", ans[i].addr, ans[i].data);48         if (rest == 0)49         {50             if (j == block - 1) printf("-1");51             else printf("%05d", ans[(j+2)*k-1].addr);52         } else53         {54             if (j == block - 1) printf("%05d", ans[(j+1)*k].addr);55             else printf("%05d", ans[(j+2)*k-1].addr);56         }57         printf("\n");58     }59     if (rest != 0)60     {61         for (i = block*k; i < n - 1; i++) printf("%05d %d %05d\n", ans[i].addr, ans[i].data, ans[i+1].addr);62         printf("%05d %d -1\n", ans[i].addr, ans[i].data);63     }64     65     return 0;66 }

 

【Zhejiang University PATest】02-1. Reversing Linked List